/*
Project: Hundredths Clock
Description: In a real circuit add transistors on each digit!
The gray wires are digits, green are the segments.
Written for common cathode displays.
Creation date: 7/10/25
Author: AnonEngineering
License: https://en.wikipedia.org/wiki/Beerware
*/
#include "RTClib.h"
const uint8_t MAX_DIGITS = 8;
const uint32_t INTERVAL = 10;
// pin definitions
const uint8_t CLOCK_PIN = 12;
const uint8_t LATCH_PIN = 11;
const uint8_t DATA_PIN = 10;
// lookup table, which segments are on for each value
const uint8_t SEG_BYTES[] = {
0xFC, /* 0 */
0x60, /* 1 */
0xDA, /* 2 */
0xF2, /* 3 */
0x66, /* 4 */
0xB6, /* 5 */
0xBE, /* 6 */
0xE0, /* 7 */
0xFE, /* 8 */
0xF6, /* 9 */
0x00 /* blank */
};
uint8_t DP_POSITION = 4;
uint32_t prevTime = 0;
uint32_t centiSeconds = 0;
RTC_DS1307 rtc;
// for hardware test only
void testDisplay() {
writeShiftDigit(0, 1, false);
writeShiftDigit(1, 2, false);
writeShiftDigit(2, 3, false);
writeShiftDigit(3, 4, true);
writeShiftDigit(4, 5, false);
writeShiftDigit(5, 6, true);
writeShiftDigit(6, 7, false);
writeShiftDigit(7, 8, false);
}
void updateDisplay(uint32_t value, uint8_t dpPos) {
uint8_t digitVal;
uint8_t powOfTen = MAX_DIGITS - 1;
uint32_t op1 = 1, op2 = 1;
for (uint8_t digit = 0; digit < powOfTen; digit++) {
for (uint8_t p = powOfTen - digit; p >= 1; p--) {
op1 = op1 * 10;
}
op2 = op1 * 10;
// with leading zero blanking (10 is a blank char)
//digitVal = value < op1 ? 10 : (value % op2) / op1;
// no blanking (better for clocks)
digitVal = (value % op2) / op1;
// fixed decimal point
//writeShiftDigit(digit, digitVal, ((dpPos - 1) == digit) ? true : false);
// "clock" decimal points
writeShiftDigit(digit, digitVal, (digit == 3 || digit == 5) ? true : false);
op1 = 1; op2 = 1;
}
// last digit is never blanked or "dotted"
writeShiftDigit(powOfTen, value % 10, false);
}
void writeShiftDigit(uint8_t digit, uint8_t number, bool dp) {
uint8_t value = SEG_BYTES[number]; // invert (~) bits for common anode
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, ~(1 << digit)); // don't invert bits (~) for common anode
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, dp ? (value | 0x01) : value);
digitalWrite(LATCH_PIN, HIGH);
}
void setup() {
Serial.begin(115200);
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (1); // hang here forever
}
}
void loop() {
DateTime now = rtc.now();
if (millis() - prevTime >= INTERVAL) {
prevTime = millis();
centiSeconds++;
if (centiSeconds == 100) centiSeconds = 0;
}
uint32_t dispValue = (now.hour() * 1000000UL) +
(now.minute() * 10000UL) +
(now.second() * 100UL) +
centiSeconds;
// update display often
updateDisplay(dispValue, DP_POSITION); // DP_POSITION not used here
//testDisplay();
}