From subsecret
Video: https://www.youtube.com/watch?v=HxVnWieD0pE
Components used:
- DCF77 Receiver: http://www.conrad.com/ce/en/product/641138/DCF-receiver-module-641138-Compatible-with-C-Control
- Arduino 101 (Also works fine with other Arduino variants)
- LCD Shield
Arduino program:
#include <TimeLib.h> #include <LiquidCrystal.h> #define READPIN 2 #define btnDOWN 13 #define ZERO_DUR_START 83L #define ZERO_DUR_END 136L #define ONE_DUR_START 178L #define ONE_DUR_END 231L #define SIGNALGAP_DUR_START 1900L #define SIGNALGAP_DUR_END 2100L #define DEBUG false int decodeMultipliers[] = {1, 1, 2, 4, 8, 10, 20, 40, 1, 1, 2, \ 4, 8, 10, 20, 1, 1, 2, 4, 8, 10, 20, 1, 2, 4, 1, 2, 4, \ 8, 10, 1, 2, 4, 8, 10, 20, 40, 80, 1, 1 }; LiquidCrystal lcd(8, 9, 4, 5, 6, 7); boolean dcf_received_date = false; boolean dcf_received_time = false; int last_dcf_hours = -1; int last_dcf_mins = -1; int last_dcf_day = -1; int last_dcf_month = -1; int last_dcf_year = -1; int last_dcf_received = millis(); void dcfTimeDateReceived(int dcf_hours, int dcf_mins, int dcf_day, int dcf_month, int dcf_year) { Serial.print("Complete: "); Serial.print(dcf_hours); Serial.print(":"); Serial.print(dcf_mins); Serial.print(" "); Serial.print(dcf_day); Serial.print("-"); Serial.print(dcf_month); Serial.print("-"); Serial.print(dcf_year); Serial.println(); setTime(dcf_hours, dcf_mins, 0, dcf_day, dcf_month, dcf_year); dcf_received_date = true; dcf_received_time = true; } void dcfIncompleteTimeDateReceived(int dcf_hours, int dcf_mins, int dcf_day, int dcf_month, int dcf_year) { Serial.print("Incomplete: "); Serial.print(dcf_hours); Serial.print(":"); Serial.print(dcf_mins); Serial.print(" "); Serial.print(dcf_day); Serial.print("-"); Serial.print(dcf_month); Serial.print("-"); Serial.print(dcf_year); Serial.println(); } void dcfOnlyTimeReceived(int dcf_hours, int dcf_mins) { Serial.print("Time: "); Serial.print(dcf_hours); Serial.print(":"); Serial.print(dcf_mins); Serial.println(); dcf_received_time = true; } void dcfOnlyDateReceived(int dcf_day, int dcf_month, int dcf_year) { Serial.print("Date: "); Serial.print(dcf_day); Serial.print("-"); Serial.print(dcf_month); Serial.print("-"); Serial.print(dcf_year); Serial.println(); dcf_received_date = true; } void setup() { Serial.begin(115200); pinMode(READPIN, INPUT_PULLUP); lcd.begin(16, 2); } unsigned long lastRef = millis(); boolean showTime = true; void printTimeToLCD() { //450 down unsigned long elap = millis() - lastRef; if (elap > 600) { int val = analogRead(0); if (val >= 430 && val <= 495) { showTime = !showTime; } lcd.clear(); if (showTime) { if (dcf_received_time && dcf_received_date) { lcd.setCursor(0, 0); twoDigitPrint(hour()); lcd.print(":"); twoDigitPrint(minute()); lcd.print(":"); twoDigitPrint(second()); lcd.setCursor(0, 1); lcd.print(day()); lcd.print("-"); lcd.print(month()); lcd.print("-"); lcd.print(year()); } else { lcd.setCursor(0, 0); lcd.print("Waiting "); lcd.print(millis() / 1000); lcd.print(" sec"); } } else { lcd.setCursor(0, 0); lcd.print("DCF "); twoDigitPrint(last_dcf_hours); lcd.print(":"); twoDigitPrint(last_dcf_mins); lcd.print(" ("); lcd.print(((millis() - last_dcf_received) / 1000)); lcd.print(")"); lcd.setCursor(0, 1); oneDigitPrint(last_dcf_day); lcd.print("-"); oneDigitPrint(last_dcf_month); lcd.print("-"); oneDigitPrint(last_dcf_year); } lastRef = millis(); } } void oneDigitPrint(int num) { if (num == -1) { lcd.print("??"); return; } lcd.print(num); } void twoDigitPrint(int num) { if (num == -1) { lcd.print("??"); return; } if (num <= 9) { lcd.print("0"); } lcd.print(num); } void loop() { unsigned long lastStartTime, signalGap, startTime, stopTime, elapsed, tmp; unsigned long sTimes[200]; int bits[200]; int i = 0; lastStartTime = 0; while (true) { startTime = millis(); stopTime = startTime; printTimeToLCD(); boolean active = digitalRead(READPIN); if (active) { while (true) { active = digitalRead(READPIN); if (active) { stopTime = millis(); } else { if (millis() < stopTime) { //arduino time wrap-around, break loop break; } tmp = millis() - stopTime; if ( tmp > 2L) { break; } } } elapsed = stopTime - startTime; signalGap = startTime - lastStartTime; lastStartTime = startTime; if ((elapsed >= ZERO_DUR_START && elapsed <= ZERO_DUR_END) || (elapsed >= ONE_DUR_START && elapsed <= ONE_DUR_END)) { if (DEBUG) { debugPrint("ACK: ", startTime, elapsed); } sTimes[i % 100] = startTime; if (elapsed >= ZERO_DUR_START && elapsed <= ZERO_DUR_END) { bits[i % 100] = 0; } if ( elapsed >= ONE_DUR_START && elapsed <= ONE_DUR_END) { bits[i % 100] = 1; } i++; if (i == 200) { i = 100; } } else { if (DEBUG) { debugPrint("REJ: ", startTime, elapsed); } } if (signalGap >= SIGNALGAP_DUR_START && signalGap <= SIGNALGAP_DUR_END) { if (DEBUG) { debugPrint("GAP: ", startTime, elapsed); } analyseSignal(i, bits, sTimes); } } } } void analyseSignal(int i, int* bits, unsigned long* sTimes) { if (i < 40) { return; } int index = i - 1; int signalArr[40]; int k = 39; for (int i = 0; i < 40; i++) { signalArr[i] = -1; } unsigned long startTime = sTimes[index % 100] - 1000L; index--; int tries = 0; while (k >= 0 && tries < 100) { tries++; unsigned long currTime = sTimes[index % 100]; int bitVal = bits[(index + 1) % 100 ]; for (int skip = 0; skip <= 4; skip++) { long tDiff = ((long)startTime) - ((long)currTime) - 1000L - skip * 1000L; if (tDiff < 0L) { tDiff = -tDiff; } if (tDiff < 20L + 10L * skip) { startTime = currTime; if (skip > 0) { for (int a = 0; a < skip; a++) { k--; } } if (k >= 0) { signalArr[k] = bitVal; } k--; break; } } index--; } boolean correctTimeStart = (signalArr[0] == 1); boolean parityMins = checkEvenParity(signalArr, 1, 8, 8); boolean parityHours = checkEvenParity(signalArr, 9, 15, 15); boolean parityDate = checkEvenParity(signalArr, 16, 38, 38); if (DEBUG) { debugSignal(signalArr, sTimes, bits, i); } for (int k = 0; k < 40; k++) { if (signalArr[k] != -1) { signalArr[k] = signalArr[k] * decodeMultipliers[k]; } } int dcf_mins = getValue(signalArr, 1, 7); int dcf_hours = getValue(signalArr, 9, 14); int dcf_day = getValue(signalArr, 16, 21); int dcf_month = getValue(signalArr, 25, 29); int dcf_year = getValue(signalArr, 30, 37); last_dcf_hours = dcf_hours; last_dcf_mins = dcf_mins; last_dcf_day = dcf_day; last_dcf_month = dcf_month; last_dcf_year = dcf_year; last_dcf_received = millis(); if (correctTimeStart && parityMins && parityHours && parityDate) { dcfTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year); } else if (correctTimeStart && parityMins && parityHours && !parityDate) { dcfOnlyTimeReceived(dcf_hours, dcf_mins); dcfIncompleteTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year); } else if (parityDate) { dcfOnlyDateReceived(dcf_day, dcf_month, dcf_year); dcfIncompleteTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year); } else { dcfIncompleteTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year); } } boolean checkEvenParity(int* arr, int startBit, int endBit, int parityBit) { int sum = 0; for (int k = startBit; k <= endBit; k++) { if (arr[k] != -1) { sum += arr[k]; } else { sum = -1; break; } } int parity = arr[parityBit]; if (sum == -1) { return false; } if (parity == -1) { return false; } if (sum % 2 == 0) { return true; } return false; } void debugPrint(String prefix, unsigned long time, unsigned long elapsed) { Serial.print(prefix); Serial.print(time); Serial.print(" - "); Serial.print(elapsed); Serial.println(); } void debugSignal(int* arr, unsigned long* st, int* bt, int i) { Serial.println("RAW Data (2 lines)"); for (int index = i - 40; index < i; index++) { Serial.print(st[index % 100]); Serial.print(","); } Serial.println(); for (int index = i - 40; index < i; index++) { Serial.print(bt[index % 100]); Serial.print(","); } Serial.println(); Serial.print("SIGNAL: "); for (int k = 0; k < 40; k++) { if (arr[k] == -1) { Serial.print("?"); } else { Serial.print(arr[k]); } Serial.print(","); } Serial.println(); } int getValue(int* arr, int startBit, int endBit) { int sum = 0; for (int k = startBit; k <= endBit; k++) { if (arr[k] != -1) { sum += arr[k]; } else { sum = -1; break; } } return sum; }