# Cwik Clock v1.0 - An Arduino Binary Clock

## Step 9: Prototyping the Display, Time Setting, and Seconds

Now that we have the base program for running a binary clock, the know-how to read from potentiometers, and are experts in using ammeters, it's time to put it all together! It may look like a rat's nest of cables and components, but you shouldn't have any issues if you follow along step-by-step.

In the following video, I use the reset switch on the Uno to start our program from the beginning (time 00:00). You can see the seconds counting on the analog meter which unfortunately has a max value of 50, not 60 (but we can open it up and swap out the background if desired). Regardless of what the meter reads, it "ticks" 60 times per minute. After a full minute, we see the time change to 00:01, and the analog meter resets. I later switch into time setting mode (this is when the orange LED at the top center turns on), at which point you can see the seconds reset to 0. I set the time to 16:59, and the moment I turn time setting mode off (the orange LED at the top center turns off), the seconds on the analog meter start to count up again. I then wait another minute, at which point the time changes to 17:00.

The Final Code
/*
Cwik Clock v1.0 - Prototyping the Display
Author: Dennis Cwik
Date: July 23, 2012

This program is the controller for a binary clock, with LEDs
attached to digital pins 0 through 10, 12, and 13. 2 potentiometers
connected to A0 and A1 control the hours and minutes respectively,
and only when A2 is pulled high. When A2 is pulled high, an LED on
pin A5 will light up to tell the user that they are in time set mode.
Finally, pin 11 is used with PWM to show the seconds on an analog
ammeter.

This example code is in the public domain.
*/

// This can be modified for debug purposes to make a minute go by quicker.
int ONE_SECOND = 1000; // measured in milliseconds
int DELAY_BETWEEN_LOOP_CALLS = 200; // measured in milliseconds

// I didn't come up with this, it's from the arduino documentation
unsigned long MAX_UNSIGNED_LONG = 4294967295; // = (2 ^ 32) - 1

int HOUR_INPUT_PIN = A0;
int MIN_INPUT_PIN = A1;
int CLOCK_MODE_SWITCH_PIN = A2;
int CLOCK_MODE_LED_PIN = A5;

// 1st column of LEDs
int PIN_MIN1 = 0;
int PIN_MIN2 = 1;
int PIN_MIN4 = 2;
int PIN_MIN8 = 3;

// 2nd column of LEDs
int PIN_MIN10 = 4;
int PIN_MIN20 = 5;
int PIN_MIN40 = 6;

// 3rd column of LEDs
int PIN_HOUR1 = 7;
int PIN_HOUR2 = 8;
int PIN_HOUR4 = 9;
int PIN_HOUR8 = 10;

// PWM on the analog meter to display seconds.
int SEC_OUTPUT_PIN = 11;

// 4th column of LEDs
int PIN_HOUR10 = 12;
int PIN_HOUR20 = 13;

// the last time the seconds in the time were incremented
unsigned long m_lastTick;

// used to tell us if we're setting the time or not
boolean m_inTimeSetMode = false;

// the time
byte m_second;
byte m_minute;
byte m_hour;

/**
* Mandatory setup routine for Arduino, is run once at the very beginning.
*/
void setup()
{
pinMode(CLOCK_MODE_LED_PIN, OUTPUT);

// initialize the pins used for outputting time
pinMode(PIN_MIN1, OUTPUT);
pinMode(PIN_MIN2, OUTPUT);
pinMode(PIN_MIN4, OUTPUT);
pinMode(PIN_MIN8, OUTPUT);
pinMode(PIN_MIN10, OUTPUT);
pinMode(PIN_MIN20, OUTPUT);
pinMode(PIN_MIN40, OUTPUT);

pinMode(PIN_HOUR1, OUTPUT);
pinMode(PIN_HOUR2, OUTPUT);
pinMode(PIN_HOUR4, OUTPUT);
pinMode(PIN_HOUR8, OUTPUT);
pinMode(PIN_HOUR10, OUTPUT);
pinMode(PIN_HOUR20, OUTPUT);

// initialize clock variables
m_lastTick = 0;
setTime(0, 0, 0);
}

/**
* Mandatory method for Arduino, it's called continuously after setup().
*/
void loop()
{
checkMode();

// see if we're setting the time, or letting time flow normally
if (m_inTimeSetMode)
{
getTimeFromPots();
}
else
{
tick();
}

// now that the time has been updated, show the time
displaySeconds();
displayMinutes();
displayHours();

// arbitrary delay so that we're not processing away 100% of the time,
// an act of power saving
delay(DELAY_BETWEEN_LOOP_CALLS);
}

/**
* A helper method to set m_hour, m_minute, and m_second.
*/
void setTime(byte newHour, byte newMinute, byte newSecond)
{
m_second = newSecond;
m_minute = newMinute;
m_hour = newHour;
}

/**
* This method keeps track of the logical flow of time. If enough time has
* passed since the last time it was called, m_second, m_minute, and m_hour
* will be updated appropriate. This takes into account that millis() rolls
* over roughly every 50 days.
*/
void tick()
{
unsigned long now = millis();
unsigned long msElapsed;

// first we need to find out how much time has passed since the last time we
// called tick()
if (now < m_lastTick)
{
// gasp, either we've succeeded in travelling back in time, or millis() wrapped around!
msElapsed = (MAX_UNSIGNED_LONG - m_lastTick) + now;
}
else
{
msElapsed = now - m_lastTick;
}

// for each second that has passed (hopefully just 1, unless our code is really laggy),
// add 1 second to the time, and increase the minutes & hours if necessary
for (int i = 0; i < msElapsed / ONE_SECOND; ++i)
{
m_lastTick = m_lastTick + ONE_SECOND;

++m_second;
if (m_second == 60)
{
m_second = 0;
++m_minute;
if (m_minute == 60)
{
m_minute = 0;
++m_hour;
if (m_hour == 24)
{
m_hour = 0;
}
}
}
}
}

/**
* This method uses PWM to display the m_second on an analog meter connected
* to SEC_OUTPUT_PIN.
*/
void displaySeconds()
{
analogWrite(SEC_OUTPUT_PIN, map(m_second, 0, 59, 0, 255));
}

/**
* This method reads the m_minute, converts it to binary, and displays
* it on the appropriate LEDs (those being PIN_MIN*).
*/
void displayMinutes()
{
byte ones = m_minute % 10;
digitalWrite(PIN_MIN1, ones & B1);
digitalWrite(PIN_MIN2, ones & B10);
digitalWrite(PIN_MIN4, ones & B100);
digitalWrite(PIN_MIN8, ones & B1000);

// division is kind of expensive, but we'll assume the compile optimizes this for us :)
byte tens = m_minute / 10;
digitalWrite(PIN_MIN10, tens & B1);
digitalWrite(PIN_MIN20, tens & B10);
digitalWrite(PIN_MIN40, tens & B100);
}

/**
* This method reads the m_hour, converts it to binary, and displays
* it on the appropriate LEDs (those being PIN_HOUR*).
*/
void displayHours()
{
byte ones = m_hour % 10;
digitalWrite(PIN_HOUR1, ones & B1);
digitalWrite(PIN_HOUR2, ones & B10);
digitalWrite(PIN_HOUR4, ones & B100);
digitalWrite(PIN_HOUR8, ones & B1000);

byte tens = m_hour / 10;
digitalWrite(PIN_HOUR10, tens & B1);
digitalWrite(PIN_HOUR20, tens & B10);
}

/**
* This method reads the values from the 2 potentiometers, converts them to
* mimnutes and hours, and sets m_minute and m_hour to the associated values.
*/
void getTimeFromPots()
{

// scale the sensor readings (from 0 to 1023) to the appropriate
// scale (0 to 23 for hours, 0 to 59 for minutes)
setTime(map(hourSensor, 0, 1023, 0, 23), map(minuteSensor, 0, 1023, 0, 59), 0);

// we set the last tick to now, because when we set m_inTimeSetMode to false,
// many seconds could have passed since the last one, and the time would jump ahead
m_lastTick = millis();
}

/**
* This method checks CLOCK_MODE_SWITCH_PIN to see if it's HIGH. If it is,
* it means we're now in clock set mode (m_inTimeSetMode is set to true), and
* turns the CLOCK_MODE_LED_PIN on.
*/
void checkMode()
{