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;
}