This clock is made of 60 LEDs and the AtMega328 chip with Arduino bootloader. Video of clock in operation. https://www.youtube.com/watch?v=L1F2BAmQfWg
Here is schematics. Board has two button to adjust hours and minutes and Real-time clock ic to keep time accurate.
Back side is not perfect because of cheap soldering iron.
Program code is below.
#include "Wire.h" boolean LEDarr[60]; unsigned long newMillis = 0; unsigned long blinkMillis = 0; int second = 0; int minute = 0; int hour = 1; unsigned long debounceTimer; boolean A2state = 1; boolean A3state = 1; void setup() { pinMode(0, OUTPUT); // matrix pinMode(1, OUTPUT); pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); pinMode(7, OUTPUT); pinMode(8, OUTPUT); // matrix pinMode(9, OUTPUT); pinMode(10, OUTPUT); pinMode(11, OUTPUT); pinMode(12, OUTPUT); pinMode(13, OUTPUT); pinMode(A0, OUTPUT); pinMode(A1, OUTPUT); pinMode(A2, INPUT_PULLUP); // buttons pinMode(A3, INPUT_PULLUP); Wire.begin(); // A4,A5 getRTC(); } int ii = 0; void loop() { unsigned long currentMillis = millis(); if (currentMillis - newMillis >= 500) { newMillis = currentMillis; getRTC(); } if(!digitalRead(A2)) { if(A2state) { A2state = 0; debounceTimer = millis(); } if(millis() - debounceTimer > 150) { A2state = 1; if(++hour == 13) hour = 1; newMillis = currentMillis; setRTC(); } } if(!digitalRead(A3)) { if(A3state) { A3state = 0; debounceTimer = millis(); } if(millis() - debounceTimer > 150) { A3state = 1; if(++minute == 60) minute = 0; newMillis = currentMillis; setRTC(); } } for(int i = 0; i <= 59; i++) LEDarr[i] = 0; if(second == 59) { if (ii < 59) for(int i = 0; i <= ii; i++) LEDarr[i] = 1; ii = ii + 2; } else { ii = 0; LEDarr[second] = 1; } LEDarr[minute] = 1; LEDarr[(hour*5)-1] = 1; if(second == (hour*5)-1 && currentMillis - blinkMillis > 200) { blinkMillis = currentMillis; LEDarr[second] = !LEDarr[second]; } if(second == minute && currentMillis - blinkMillis > 200) { blinkMillis = currentMillis; LEDarr[second] = !LEDarr[second]; } if(minute == (hour*5)-1 && currentMillis - blinkMillis > 200) { blinkMillis = currentMillis; LEDarr[minute] = !LEDarr[minute]; } LEDloop(); } byte decToBcd(byte val) { return ((val/10*16) + (val%10)); } byte bcdToDec(byte val) { return ((val/16*10) + (val%16)); } void setRTC() { Wire.beginTransmission(0x51); Wire.write(0x03); //Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour-1)); Wire.endTransmission(); } void getRTC() { Wire.beginTransmission(0x51); Wire.write(0x02); Wire.endTransmission(); Wire.requestFrom(0x51, 3); second = bcdToDec(Wire.read() & B01111111); // remove VL error bit minute = bcdToDec(Wire.read() & B01111111); // remove unwanted bits from MSB hour = bcdToDec(Wire.read() & B00111111); if(hour >= 12) hour = hour - 12; hour = hour + 1; } void LEDloop() { int led = 0; for(int a = 8; a <= 15; a++) { if (a <= 13) digitalWrite(a, 1); else if(a == 14) digitalWrite(A0, 1); else if(a == 15) digitalWrite(A1, 1); if(a != 8) { for(int i = 4; i <= 7; i++) { digitalWrite(i, !LEDarr[led++]); delayMicroseconds(340); digitalWrite(i, 1); } } for(int i = 0; i <= 3; i++) { digitalWrite(i, !LEDarr[led++]); delayMicroseconds(340); digitalWrite(i, 1); } if (a <= 13) digitalWrite(a, 0); else if(a == 14) digitalWrite(A0, 0); else if(a == 15) digitalWrite(A1, 0); } }