Well I finally wired this all up on the breadboard and left it running for about half a day, but it has some serious time loss issues.
As you can see it is running with the internal clock at 8Mhz as there is no external crystal.
Writing this then made me realise why it is losing so much time – my previous test was with a 16MHz crystal and counting to 16000 for each second.
I dropped the counter to 8000 and it was now about 2 seconds fast per minute, so I upped it to 8192 and it is now pretty close to exactly a minute, I let it run for a bit before adjusting further to 8200, this has run for about a day now and is still telling good time.
There is a little flicker across the LEDs occasionally depending on how many are lit, and some of the Red Hour LEDs seem to have a very low level of light when other LEDs are lit.
The latter condition is due to a forward voltage issue with Charlieplexing, whereby a small amount of voltage is hitting the Red LEDs and causing them to light due to shorter current paths, and Red LEDs lighting at around 1.3V compared to Blue at around 3V.
I could get around this issue by either using LEDs of all the same colour, LEDs that all have the same forward voltage or adding some additional diodes to the Red connections, similar issues would also be seen with RGB LEDs in a charlieplex configuration.
I may also try adding NPN transistors in an emitter follower configuration to make them brighter and reduce the load on the I/O ports.
I have also developed another version of this clock, but using the DS1307 real time clock chip mentioned in the previous post, just to see how easy/difficult it was from both a hardware and software perspective.
I built this one on the breadboard as well, here is the schematic:
And here is the code – most of it is simply the “set time” example that comes with the DS1307 Arduino library joined up with my code for displaying the time on the Charlieplexed LEDs, and some debug serial output:
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#define DEBUG 1 // set debug mode (2 = all debug, 1 = just time)
const int nPins = 3;
const int pins[] = {6, 7, 8};
const int clock[6][2] = { {7, 8}, {8, 7}, {6, 7}, {7, 6}, {6, 8}, {8, 6} };
const char *monthName[12] = { “Jan”, “Feb”, “Mar”, “Apr”, “May”, “Jun”, “Jul”, “Aug”, “Sep”, “Oct”, “Nov”, “Dec”
};
tmElements_t tm;
int lastsec = 0;
void setup() {
bool parse=false;
bool config=false;
// RTC should keep time with just battery and not actually need this section to run
if (getDate(__DATE__) && getTime(__TIME__)) { // get the date and time the compiler was run
parse = true;
//if (makeTime(tm) < now()) {
if (RTC.write(tm)) { // and configure the RTC with this info
config = true;
}
//}
}
#ifdef DEBUG // debug output
Serial.begin(9600); // set serial port speed
while (!Serial); // wait for serial connection
delay(200);
Serial.println(“LedPlex4 Debug Output”);
Serial.println(“=====================”);
if (parse && config) {
Serial.print(“DS1307 configured Time=”);
Serial.print(__TIME__);
Serial.print(“, Date=”);
Serial.println(__DATE__);
//Serial.println(makeTime(tm));
//Serial.println(now());
} else if (parse) {
Serial.println(“DS1307 Communication Error :-{“);
Serial.println(“Please check your circuitry”);
} else {
Serial.print(“Could not parse info from the compiler, Time=””);
Serial.print(__TIME__);
Serial.print(“”, Date=””);
Serial.print(__DATE__);
Serial.println(“””);
}
#endif
}
bool getTime(const char *str)
{
int Hour, Min, Sec;
if (sscanf(str, “%d:%d:%d”, &Hour, &Min, &Sec) != 3) return false;
tm.Hour = Hour;
tm.Minute = Min;
tm.Second = Sec;
return true;
}
bool getDate(const char *str)
{
char Month[12];
int Day, Year;
uint8_t monthIndex;
if (sscanf(str, “%s %d %d”, Month, &Day, &Year) != 3) return false;
for (monthIndex = 0; monthIndex < 12; monthIndex++) {
if (strcmp(Month, monthName[monthIndex]) == 0) break;
}
if (monthIndex >= 12) return false;
tm.Day = Day;
tm.Month = monthIndex + 1;
tm.Year = CalendarYrToTm(Year);
return true;
}
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();
}
#if DEBUG == 2 // 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() {
tmElements_t tm;
if (RTC.read(tm)) {
showtime(tm.Second, 6, 0); // Display seconds (LEDs 0-5)
//showtime(tm.Minute, 6, 6); // Display minutes (LEDs 6-11)
//showtime(tm.Hour, 5, 12); // Display hours (LEDs 12-16)
}
#ifdef DEBUG // Debug output
if (lastsec != tm.Second) {
lastsec = tm.Second;
Serial.print(“Hours: “);
Serial.print(tm.Hour, DEC);
Serial.print(” Minutes: “);
Serial.print(tm.Minute, DEC);
Serial.print(” Seconds: “);
Serial.print(tm.Second, DEC);
Serial.println(“”);
}
#endif
}