From subsecret
(Created blank page) |
No edit summary |
||
Line 1: | Line 1: | ||
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; | |||
} |
Latest revision as of 21:31, 28 April 2017
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; }