I have recently been reading about the use of timers on AVR chips over at Max Embedded and thought this would be a perfect opportunity to update my binary clock once again.
I decided to make use of the CTC option, whereby it clears a timer on compare, you set a value for the timer to check against and then an interrupt service routine is called every time the compare is successful, and the counter automatically resets itself and starts all over again.
This also removes the requirement for the connection between pins 5 and 6 previously used for the tone pin (pin 6) and the interrupt generated by that tone on pin 5.
The new code compiles up even smaller to just 1900 bytes which is even smaller than the 2264 bytes for the PWM version.
This is the new code:
#include <Bounce.h>
#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(BUTTON1, 5); // set 5ms debounce for BUTTON1
Bounce button2 = Bounce(BUTTON2, 5); // set 5ms debounce for BUTTON2
void setup() {
TCCR1B |= (1 << WGM12); // enable CTC mode on timer 1
OCR1A = 7999; // initialise compare value 8MHz/1*(8000-1) = 1ms
TCNT1 = 0; // initialise counter for timer 1
TIMSK1 |= (1 << OCIE1A); // enable compare interrupt
sei(); // enable interrupts
pinMode(BUTTON1, INPUT); // setup button1 for input
pinMode(BUTTON2, INPUT); // setup button2 for input
}
ISR (TIM1_COMPA_vect) { // ISR triggered every 1ms
masterClock++; // 1ms tick
if (masterClock >= 1000) { // 1000ms = 1s
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)
}