Skip to content

Instantly share code, notes, and snippets.

@Lukelectro
Last active February 28, 2026 20:55
Show Gist options
  • Select an option

  • Save Lukelectro/24a3847f5a7d357eb5bd060d50728bc2 to your computer and use it in GitHub Desktop.

Select an option

Save Lukelectro/24a3847f5a7d357eb5bd060d50728bc2 to your computer and use it in GitHub Desktop.
DCF-77 clock on 50228 display
//select atmega161 from majorcore, at 8Mhz external oscilator. DCF-77 receiver is connected to PE0, arduino pin 32, INT2.
#include <dcf77.h> // Udo Klein Blinkenlight DCF77 crystal library
#include <MSL50228.h> //for the displays
const uint8_t dcf77_sample_pin = 32; // 32 PE0 INT2
const uint8_t dcf77_inverted_samples = 1;
const uint8_t dcf77_pin_mode = INPUT_PULLUP; // enable internal pull up
const uint8_t dcf77_monitor_led = -1; // Not used
MSL50228 display;
uint8_t ledpin(const uint8_t led) {
return led;
}
uint8_t sample_input_pin() {
const uint8_t sampled_data =
dcf77_inverted_samples ^ digitalRead(dcf77_sample_pin);
digitalWrite(ledpin(dcf77_monitor_led), sampled_data);
return sampled_data;
}
void setup() {
using namespace Clock;
Serial.begin(115200);
sprintln();
sprintln(F("Simple DCF77 Clock V3.1.1"));
sprintln(F("(c) Udo Klein 2016"));
sprintln(F("www.blinkenlight.net"));
sprintln();
sprint(F("Sample Pin: "));
sprintln(dcf77_sample_pin);
sprint(F("Sample Pin Mode: "));
sprintln(dcf77_pin_mode);
sprint(F("Inverted Mode: "));
sprintln(dcf77_inverted_samples);
sprint(F("Monitor Pin: "));
sprintln(ledpin(dcf77_monitor_led));
sprintln();
sprintln();
sprintln(F("Initializing..."));
pinMode(ledpin(dcf77_monitor_led), OUTPUT);
pinMode(dcf77_sample_pin, dcf77_pin_mode);
DCF77_Clock::setup();
DCF77_Clock::set_input_provider(sample_input_pin);
display.write("Waitfor sync");
// Wait till clock is synced, depending on the signal quality this may take
// rather long. About 5 minutes with a good signal, 30 minutes or longer
// with a bad signal
for (uint8_t state = Clock::useless;
state == Clock::useless || state == Clock::dirty;
state = DCF77_Clock::get_clock_state()) {
// wait for next sec
Clock::time_t now;
DCF77_Clock::get_current_time(now);
// render one dot per second while initializing
static uint8_t count = 0;
sprint('.');
++count;
if (count == 60) {
count = 0;
sprintln();
}
if (count % 2) {
display.writeAt(5, "+");
} else {
display.writeAt(5, "*");
}
}
display.writeAt(5, " "); // clear the dot.
}
void paddedPrint(BCD::bcd_t n) {
sprint(n.digit.hi);
sprint(n.digit.lo);
}
void loop() {
Clock::time_t now;
char disps[6][4];
static bool onOFF = false;
DCF77_Clock::get_current_time(now);
if (now.month.val > 0) {
switch (DCF77_Clock::get_clock_state()) { // only print seconds when they are reliable (Clock locked or even synced)
case Clock::useless:
default:
sprint(F("useless "));
disps[4][0] = 'F';
disps[4][1] = 'O';
disps[4][2] = 'U';
disps[4][3] = 'T';
//when clock is useless, print "FOUT" (Meaning "WRONG" but convieniently 4 letters so it fits the display ;))
break;
case Clock::dirty:
sprint(F("dirty: "));
disps[4][0] = ' ';
disps[4][1] = ' ';
disps[4][2] = '?';
disps[4][3] = '?';
break;
case Clock::free:
sprint(F("free: "));
disps[4][0] = '?';
disps[4][1] = '?';
disps[4][2] = now.second.digit.hi + '0';
disps[4][3] = now.second.digit.lo + '0';
break;
case Clock::unlocked:
sprint(F("unlocked: "));
disps[4][0] = ' ';
disps[4][1] = '?';
disps[4][2] = now.second.digit.hi + '0';
disps[4][3] = now.second.digit.lo + '0';
break;
case Clock::synced:
sprint(F("synced: "));
disps[4][0] = ' ';
disps[4][1] = ' ';
disps[4][2] = now.second.digit.hi + '0';
disps[4][3] = now.second.digit.lo + '0';
break;
case Clock::locked:
sprint(F("locked: "));
disps[4][0] = ' ';
disps[4][1] = ' ';
disps[4][2] = now.second.digit.hi + '0';
disps[4][3] = now.second.digit.lo + '0';
break;
}
sprint(' ');
sprint(F("20"));
paddedPrint(now.year);
sprint('-');
paddedPrint(now.month);
sprint('-');
paddedPrint(now.day);
sprint(' ');
paddedPrint(now.hour);
sprint(':');
paddedPrint(now.minute);
sprint(':');
paddedPrint(now.second);
sprint("+0");
sprint(now.uses_summertime ? '2' : '1');
sprintln();
disps[0][0] = now.hour.digit.hi + '0'; // +'0' converts number to ASCII ;)
disps[0][1] = now.hour.digit.lo + '0';
disps[0][2] = ' ';
disps[0][3] = ' ';
disps[2][0] = ' ';
disps[2][1] = now.minute.digit.hi + '0';
disps[2][2] = now.minute.digit.lo + '0';
disps[2][3] = ' ';
disps[1][0] = now.day.digit.hi + '0';
disps[1][1] = now.day.digit.lo + '0';
disps[1][2] = ' ';
disps[1][3] = ' ';
if (now.month.digit.hi == 0) {
switch (now.month.digit.lo) {
case 1:
disps[3][0] = 'J';
disps[3][1] = 'a';
disps[3][2] = 'n';
break;
case 2:
disps[3][0] = 'F';
disps[3][1] = 'e';
disps[3][2] = 'b';
break;
case 3:
disps[3][0] = 'M';
disps[3][1] = 'a';
disps[3][2] = 'r';
break;
case 4:
disps[3][0] = 'A';
disps[3][1] = 'p';
disps[3][2] = 'r';
break;
case 5:
disps[3][0] = 'M';
disps[3][1] = 'e';
disps[3][2] = 'i';
break;
case 6:
disps[3][0] = 'J';
disps[3][1] = 'u';
disps[3][2] = 'n';
break;
case 7:
disps[3][0] = 'J';
disps[3][1] = 'u';
disps[3][2] = 'l';
break;
case 8:
disps[3][0] = 'A';
disps[3][1] = 'u';
disps[3][2] = 'g';
break;
case 9:
disps[3][0] = 'S';
disps[3][1] = 'e';
disps[3][2] = 'p';
break;
}
} else {
switch (now.month.digit.lo) {
case 0:
disps[3][0] = 'O';
disps[3][1] = 'k';
disps[3][2] = 't';
break;
case 1:
disps[3][0] = 'N';
disps[3][1] = 'o';
disps[3][2] = 'v';
break;
case 2:
disps[3][0] = 'D';
disps[3][1] = 'e';
disps[3][2] = 'c';
break;
}
}
disps[3][3] = ' '; // set all unused ones to spaces (So the uninitialised content does not acidentaly blank a display)
disps[5][0] = '2';
disps[5][1] = '0';
disps[5][2] = now.year.digit.hi + '0';
disps[5][3] = now.year.digit.lo + '0';
display.clear();
display.writeAt(0, disps[0]);
display.writeAt(1, disps[1]);
display.writeAt(2, disps[2]);
display.writeAt(3, disps[3]);
display.writeAt(4, disps[4]);
display.writeAt(5, disps[5]);
// display is quite hungry, so only on when button_down is pressed or at the start of the hour, or when it is switched on with button_up
if ((digitalRead(B_DOWN) == 0) || now.minute.val == 0 || onOFF == true) {
display.setBrightness(3);
} else {
display.setBrightness(0);
}
if (digitalRead(B_UP) == 0) {
while (digitalRead(B_UP) == 0) delay(100);
onOFF = !onOFF;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment