Close

Binary Clock 4

I recently re-read an article, I had originally read some time ago, about an arduino clock source using a single wire, on Instructables by relic1974, and thought that this might possibly be a more accurate clock signal than the tone value I am currently using.

The internal timer is not overly accurate and there seems to be enough fluctuation in the tone output to cause my clock to gain or lose seconds over a relatively short period of time.

There are no required changes to my board layout as since as with most of the pins on an ATtiny44, D3 is also an analog pin (A7), in addition to which it is also one of 4 PWM capable pins.

Using a PWM signal makes for slightly smaller hex code as I would no longer require the tone() function, as it would be replaced with an analogWrite() function instead.

The binary sketch size is 3072 bytes for  the tone() version and 2264 bytes for the PWM version,

I was not exactly strapped for space on my ATtiny44 chip, but now it will even fit on an ATtiny24 chip.

I have also decided to make use of bounce2, newer more enhanced debounce code, which requires a couple more changes.

The full version of the new code is posted below:

#include <Bounce2.h>

#define TONEPIN 7           // Analog pin 7 (pa7) used as PWM output
#define BUTTON1 1           // digital pin 0 (pb1) used to set clock
#define BUTTON2 4           // digital pin 6 (pa6) used to set clock

int masterClock = 0;
int lastsec = 0;
int seconds = 0;
int minutes = 0;
int hours = 0;
int hms = 0;
int sw1 = 0;
int sw2 = 0;
int both = 0;
boolean sw1on = false;
boolean sw2on = false;
boolean bothon = false;

const int nPins = 5;
const int pins[] = {6, 7, 8, 9, 10};
const int clock[17][2] = { {6, 7}, {6, 8}, {7, 8}, {8, 9}, {8, 10}, {9, 10},    // Seconds LEDs
                           {7, 6}, {8, 6}, {8, 7}, {9, 8}, {10, 8}, {10, 9},    // Minutes LEDs
                           {9, 6}, {6, 9}, {6, 10}, {10, 7}, {7, 10} };         // Hours LEDs

Bounce button1 = Bounce();
Bounce button2 = Bounce();

void setup() {
  attachInterrupt(0, tick, CHANGE); // call ISR on change to INT0 (digital pin 2)
  analogReference(DEFAULT);  // default 5V reference
  analogWrite(TONEPIN, 127); // start PWM with 50% duty cycle as clock input for ISR
  pinMode(BUTTON1, INPUT);   // setup button1 for input
  pinMode(BUTTON2, INPUT);   // setup button2 for input
  button1.attach(BUTTON1);
  button1.interval(5);       // set 5ms debounce interval for BUTTON1
  button2.attach(BUTTON2);
  button2.interval(5);       // set 5ms debounce interval for BUTTON2
}

void tick() {                // Interrupt Service Routine to generate 1 second “tick”
  masterClock++;             // increment clock counter
  if (masterClock >= 979) {  // 980 ticks reached (490Hz * 2)
    seconds++;               // increment seconds
    masterClock = 0;         // reset masterClock
  }
}

void turnon(int led) {
  int Vcc = clock[led][0];
  int Gnd = clock[led][1];
  pinMode(Vcc, OUTPUT);
  pinMode(Gnd, OUTPUT);
  digitalWrite(Vcc, HIGH);
  digitalWrite(Gnd, LOW);
}

void alloff() {
  for (int i = 0; i < nPins; i++) {
    digitalWrite(pins[i], LOW);
    pinMode(pins[i], 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();
      }
  }
}

void loop() {
  // Check if buttons have been pressed  
  button1.update();                // update button1
  button2.update();                // update button2
  sw1 = button1.read();            // button 1 state
  sw2 = button2.read();            // button 2 state
  both = sw1 && sw2;               // both state

  if (sw1 == 0) sw1on = false;
  if (sw2 == 0) sw2on = false;
  if (both == 0) bothon = false;

  // toggle setup states if both buttons are pressed and then released together
  if (both && !bothon) {
    if (hms == 0) hms=1;       // toggle hours/minutes/seconds to hours if entering setup mode
    else hms = 0;              // toggle hours/minutes/seconds to off if leaving setup mode
    bothon = true;             // set flag for both buttons on
  }

  // set hours(1), minutes(2), or seconds(3)
  if ((hms != 0) && sw1 && !sw1on && !bothon) {
    hms++;                            // toggle hours/minutes/seconds
    if (hms == 4) hms = 1;            // reset back to hours if hms goes beyond seconds
  sw1on = true;
  }
  
  if ((hms != 0) && sw2 && !sw2on && !bothon) {
    if (hms == 1) {
      hours++;
      if (hours == 24) hours = 0;
    }
    if (hms == 2) {
      minutes++;
      if (minutes == 60) minutes = 0;
    }
    if (hms == 3) {
      seconds = 0;
    }
    sw2on = true;
  }
    
  // Adjust the time based on seconds passed
  if (seconds == 60) {
    minutes++;                // increment minutes when seconds reach 60
    if (minutes == 60) {
      hours++;                // increment hours when minutes reach 60
      if (hours == 24) {
        hours = 0;            // reset hours when hours reaches 24
      }
      minutes = 0;            // reset minutes when minutes reaches 60
    }
    seconds = 0;              // reset seconds when seconds reaches 60
  }
  
  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)
}

Leave a Reply