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.
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)
}