Close

Binary Clock

For a while now I have wanted to build a binary clock, simply because they are cool, but not wanted to pay the price of some of the shop bought items.

I decided that I would not use the classic binary coded decimal, but instead use binary coded sexagesimal, as it makes use of fewer LEDs and makes it even more difficult to read for those not used to binary.

I also decided I wanted to make use of charlieplexing so as to make best use of the pins available on a given microcontroller.

First I mocked up a suitable circuit on a breadboard using an ATMega168 and half a dozen LEDs and was trying out the Arduino charlieplex library, the coding looked to be simple enough, I could make it compile, but could not actually make it light any of the LEDs.

I eventually gave up with this library and went with direct control of the pins with the pinMode() and digitalWrite() functions.

I was originally going to use a real time clock DS1037 chip connected via I2C, but then read about using the tone() function and the liked possibility of using that as an Interrupt Service Routine (ISR) trigger.

I played around with the code and eventually managed to cobble something together that seemed to work, it has the option of providing serial output when in debug mode – this is so I could check that the maths/shift parts were all doing what they were supposed to, that code can all be removed once I confirm it all works correctly and I re-compile it for an ATTiny44.

I only have enough space on my breadboard, without giving myself serious headaches, to wire up the 6 seconds LEDs via 3 inputs, but if that works then the theory is sound and it can be expanded out for all 15 LEDs on 5 inputs.

The schematic shows how the 15 charlieplexed LEDs connect to the 5 pins of the ATTiny44.
I have also drawn up a simple perf board layout for the clock using DIY Layout Creator, which is a little limited with regards components, but is much easier to master than say Eagle, and for the quantity/density of LEDs I am using, much clearer than Fritzing.

The code below works for the seconds, with an ATMega168 on my breadboard. The “clock” array needs expanding to include the LEDs for hours and minutes, at which point the “showtime” lines for minutes and hours can be uncommented.

There are 2 buttons in the design and I have chosen to use the Arduino Bounce Library to debounce the button presses, the buttons are intended to be used in the same way as on simple digital watches – both buttons to enter/leave setup mode, then one cycles through hours, minutes, seconds, the other increments the current value.

#include <Bounce.h>                  // include debounce functions

#define TONEPIN 4                    // digital pin 4 (pd4) used as tone output
#define BUTTON1 5                    // digital pin 5 (pd5) used to set clock
#define BUTTON2 6                    // digital pin 6 (pd6) used to set clock
//#define DEBUG 1                    // set debug mode

// Initialise variables
int DELAY_TIME = 1000;
int masterClock = 0;
int seconds = 0;
int minutes = 0;
int hours = 0;
int hms = 0;
boolean sw1 = false;
boolean sw2 = false;
boolean both = false;
boolean sw1on = false;
boolean sw2on = false;
boolean sw1off = false;
boolean sw2off = false;
const int nPins = 3;
const int pins[] = {9, 10, 11};
const int clock[6][2] = { {10,11}, {11,10}, {9, 10}, {10, 9}, {9, 11}, {11, 9} };

Bounce button1 = Bounce(BUTTON1, 5);  // set 5ms debounce for BUTTON1
Bounce button2 = Bounce(BUTTON2, 5);  // set 5ms debounce for BUTTON2

void setup() {
  Serial.begin(9600);
  attachInterrupt(1, tick, RISING);   // call ISR on rising input to INT1 (digital pin 3)
  pinMode(TONEPIN, OUTPUT);           // setup tonepin for output
  tone(TONEPIN, 8000);                // generate 8000Hz tone on digital pin 4 to act as clock input for ISR
  pinMode(BUTTON1, INPUT);            // setup button1 for input
  pinMode(BUTTON2, INPUT);            // setup button2 for input
}

// Interrupt Service Routine to generate 1 second “tick”
void tick() {
  masterClock++;                      // increment clock counter
  if (masterClock == 16000) {         // 8000 reached
    seconds++;                        // increment seconds
    masterClock = 0;                  // reset masterClock
  }
}

// Turn on an LED
void turnon(int led) {
  int Vcc = clock[led][0];            // set positive pin
  int Gnd = clock[led][1];            // set ground pin
  pinMode(Vcc, OUTPUT);               // set positive pin for OUTPUT
  pinMode(Gnd, OUTPUT);               // set ground pin for OUTPUT
  digitalWrite(Vcc, HIGH);            // Turn on LED
  digitalWrite(Gnd, LOW);             // Turn off ground pin
}

// Turn off all LEDs
void alloff() {
  for (int i = 0; i < nPins; i++) {
    digitalWrite(pins[i], LOW);       // turn off all LEDs
    pinMode(pins[i], INPUT);          // set all pins to INPUT
  }
}

void showtime(int Value, int Width, int Offset) {
  int mask;
    for (int i = 0; i < Width; i++) {
      mask = 1 << i;                  // shift bit mask by current position
      if (HIGH && (Value & mask)) {   // check if LED should be lit
        turnon(Offset + i);           // turn on the LED
        alloff();                     // turn off all LEDs
      }

#ifdef DEBUG                          // debug output
      Serial.print(“Mask: “);
      Serial.print(mask, BIN);
      Serial.print(” On or Off: “);
      Serial.print(HIGH && (Value & mask), BIN);
      Serial.print(” LED: “);
      Serial.print(Offset + i, DEC);
      Serial.println(“”);
#endif
  }
}

void loop() {
  // Check if buttons have been pressed  
  button1.update();                    // update button1
  button2.update();                    // update button2
  sw1on = button1.risingEdge();        // button 1 pressed
  sw1off = button1.fallingEdge();      // button 2 pressed
  sw2on = button2.risingEdge();        // button 1 released
  sw2off = button2.fallingEdge();      // button 2 released
  
  // toggle stup option: hours(1), minutes(2) or seconds(3)
  if ((hms != 0) && sw1on) sw1 = true; // button1 pressed
  if ((hms != 0) && sw1off && sw1) {   // button1 released
    sw1 = false;                       // reset button 1 state
    hms++;                             // toggle hours/minutes/seconds
    if (hms = 4) hms = 1;              // reset back to hours if hms goes beyond seconds
  }
  
  // set hours(1), minutes(2) or seconds(3)
  if ((hms != 0) && sw2on) sw2=true;   // button2 pressed
  if ((hms != 0) && sw2off && sw2) {   // button2 released
    if (hms = 1) {
      hours++;                         // increment hours
      if (hours = 60) hours = 0;       // reset houts to 0 if we reach 60
    }
    if (hms = 2) {
      minutes++;                       // increment minutes
      if (minutes = 60) minutes = 0;   // reset minutes to 0 if we reach 60
    }
    if (hms = 3) seconds = 0;          // set seconds to 0
  }
    
  // toggle setup states if both buttons are pressed and then released together
  if (sw1on && sw2on) both = true;     // both buttons pressed
  if (sw1off && sw2off && both) {      // both buttons released
    both = false;                      // reset dual button status
    if (hms == 0) hms=1;               // toggle hours/mins/sec to hours if entering setup mode
    else hms = 0;                      // toggle hours/minutes/secs to off if leaving setup mode
  }
  
  // Adjust the time based on seconds passed
  if (seconds == 60) {
    minutes++;                         // increment minutes when seconds resch 60
    if (minutes == 60) {
      hours++;                         // increment hours when minutes reach 60
      if (hours == 24) {
        hours = 0;                     // reset hours
      }
      minutes = 0;                     // reset minutes
    }
    seconds = 0;                       // reset seconds
  }
  
  showtime(seconds, 6, 0);             // Display seconds (LEDs 0-5)
  //showtime(minutes, 6, 6);           // Display minutes (LEDs 6-11)
  //showtime(hours, 5, 12);            // Display hours (LEDs 12-16)

#ifdef DEBUG                           // Debug output
  Serial.print(“Hours: “);
  Serial.print(hours, DEC);
  Serial.print(” Minutes: “);
  Serial.print(minutes, DEC);
  Serial.print(” Seconds: “);
  Serial.print(seconds, DEC);
  Serial.println(“”);
#endif
}

Leave a Reply