oui j'en ai tester beaucoup
ca fonctionne mais de gros probleme pour la reception
ca fonctionne pas tous les jours j'avais utilise ce code arduino nano
#include <TimeLib.h>
#define DCF77PIN 2 // input - DCF signal from antenna pcb. Pin must an interrupt input!
#define DCF_INTERRUPT 0 // Interrupt number associated with pin
#define LED_LEAPYEAR 31 // output - LED - Leap year
#define LED_DCFSTATUS 42 // output - LED - On when we have good DCF data
// Pulse flanks
static unsigned long leadingEdge = 0;
static unsigned long trailingEdge = 0;
unsigned long previousLeadingEdge = 0;
int bufferPosition = 0;
// used in <Int0handler>
volatile unsigned int DCFSignalState = 0; // interrupt variables ALWAYS need volatile qualifier!!
boolean errorCondition = false;
// used in <loop>
int previousSecond = 0;
unsigned int previousSignalState = 0;
// DCF Buffers and indicators
static int DCFbitBuffer[59]; // here, the received DCFbits are stored
const int bitValue[] = {1, 2, 4, 8, 10, 20, 40, 80}; // these are the decimal values of the received DCFbits
// dcf variables to store decoded DCF time in
int dcfMinute = 0;
int dcfHour = 0;
int dcfDay = 0;
int dcfWeekDay = 0;
int dcfMonth = 0;
int dcfYear = 0;
int dcfDST = 0;
int leapYear = 0;
// variables to check if DCF bits are valid
bool dcfValidSignal = false;
int dcfP1counter = 0;
int dcfP2counter = 0;
int dcfP3counter = 0;
int dcfParityCheckP1 = 0;
int dcfParityCheckP2 = 0;
int dcfParityCheckP3 = 0;
// variables used to store weeknumber and daynumber values
int dayNumber;
int weekNumber;
// only after start on a new minute, display received bits on inner LED ring
boolean MinuteMarkerFlag = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(DCF77PIN, INPUT);
initialize();
attachInterrupt(DCF_INTERRUPT, int0handler, CHANGE);
}
//================================================================================================================
//
// Function name : processDcfBit
// called from : <scanSignal>
//
// Purpose : after reception of one good DCF bit, do some checks and save it in the DCFbitBuffer array
// Parameters : none
// Return value : none
//
//================================================================================================================
void processDcfBit(int dcfBit)
{
//--------------------------------------------------------------------
// display incoming DCF bits on inner LED ring
//--------------------------------------------------------------------
// only if we have valid DCF data or after an Minute Mark (EoM) signal
//--------------------------------------------------------------------
// // Fill DCFbitBuffer array with DCFbit
//--------------------------------------------------------------------
DCFbitBuffer[bufferPosition] = dcfBit;
//--------------------------------------------------------------------
// Parity check
//--------------------------------------------------------------------
// DURING reception of the DCF bits, calculate and display the results of the DCF parity check.
//
// There is a Parity bit for the minutes, the hours and for the date.
// DCF77 works with EVEN parity, this works as follows:
// The hours for example have 6 bits plus a paritybit. The bits with value 1 are add up including the paritybit,
// the result must be an even number. If there is a bit wrong received, a 0 is as 1, or a 1 is as 0 received,
// then the result is uneven. source: http://www.picbasic.nl/frameload_uk.htm?http://www.picbasic.nl/info_dcf77_uk.htm
if (bufferPosition == 0)
{
// reset variables
dcfP1counter = 0;
dcfP2counter = 0;
dcfP3counter = 0;
dcfParityCheckP1 = 0;
dcfParityCheckP2 = 0;
dcfParityCheckP3 = 0;
}
// ----------------------------------------
// First parity check: minute bits
// ----------------------------------------
if (bufferPosition == 28)
{
for (int i = 21; i <= 27; i++)
{
// count the number of bits with the value '1'
dcfP1counter += DCFbitBuffer;
}
// perform P1 parity check. Parity is OK if the sum is an EVEN value
if ((DCFbitBuffer[28] + dcfP1counter) % 2 == 0)
{
// Parity P1 PASS
dcfParityCheckP1 = 1;
}
else
{
// we have no valid data!
dcfValidSignal = false;
}
}
// ----------------------------------------
// Second parity check: hour bits
// ----------------------------------------
if (bufferPosition == 35)
{
for (int i = 29; i <= 34; i++)
{
dcfP2counter += DCFbitBuffer;
}
// perform P2 parity check. Parity is OK if the sum is an EVEN value
if ((DCFbitBuffer[35] + dcfP2counter) % 2 == 0)
{
// Parity P2 PASS
dcfParityCheckP2 = 1;
}
else
{
// we have no valid data!
dcfValidSignal = false;
}
}
// ----------------------------------------
// Third parity check: date bits
// ----------------------------------------
if (bufferPosition == 58)
{
for (int i = 36; i <= 57; i++)
{
dcfP3counter += DCFbitBuffer;
}
// perform P3 parity check. Parity is OK if the sum is an EVEN value
(DCFbitBuffer[58] + dcfP3counter) % 2 == 0 ? dcfParityCheckP3 = 1 : dcfParityCheckP3 = 0;
// Turn Parity2 'PASS' or 'FAIL' LED ON
if (dcfParityCheckP3 == 1)
{
// Parity P3 PASS
dcfParityCheckP3 = 1;
}
else
{
// we have no valid data!
dcfValidSignal = false;
// Turn DCF OK LED OFF
}
// ----------------------------------------
// finally, check all Parity bits
// ----------------------------------------
dcfParityCheckP1 + dcfParityCheckP2 + dcfParityCheckP3 == 3 ? dcfValidSignal = true : dcfValidSignal = false;
}
//--------------------------------------------------------------------
// before continuing with the next bit, increment counter
//--------------------------------------------------------------------
bufferPosition++;
//--------------------------------------------------------------------
// check if we have not received too many pulses?
//--------------------------------------------------------------------
if (bufferPosition > 59)
{
// Buffer Overflow ERROR - we have received more pulses before reaching
// the 2 second 'gap' signalling the end of the minute.
//This error may be due to a noisy signal giving addition peaks/dcfBits
// So clear both DCFbit displays and start again.
// Buffer Overflow ERROR - nous avons reçu plus d'impulsions avant d'atteindre
// le 'gap' de 2 secondes signalant la fin de la minute.
//Cette erreur peut être due à un signal bruité donnant des pics d'addition/dcfBits
// Donc, effacez les deux affichages DCFbit et recommencez.
// Reset buffer counter
bufferPosition = 0;
// turn Buffer Overflow Error LED ON
// exit
return;
}
//--------------------------------------------------------------------
// everything OK so we wait for next incoming DCFbit
// tout va bien donc nous attendons le prochain DCFbit entrant
//--------------------------------------------------------------------
}
//================================================================================================================
//
// bitDecode
//
// called from <processBuffer>
//================================================================================================================
int bitDecode(int bitStart, int bitEnd)
{
// reset 'bitValue-array' counter
int i = 0;
int value = 0;
// process bitrange bitStart > bitEnd
while (bitStart <= bitEnd)
{
// check if DCFbit in buffer is '1', discard when '0'
if (DCFbitBuffer[bitStart] == 1)
{
// DCFbit in buffer == 1 so append its corresponding value to the variable 'value'
// DCFbit in buffer == 1 donc ajouter sa valeur correspondante à la variable 'value'
value = value + bitValue;
}
// increment 'bitValue-array' counter
i++;
// increment bit-range counter
bitStart++;
}
return value;
}
//================================================================================================================
//
// Function name : dayWeekNumber
// called from : <decodeBufferContents>
//
// Purpose : calculate the WEEK number according to ISO standard, see comments in the ARCHIVE below
// calculer le numéro de SEMAINE selon la norme ISO, voir les commentaires dans l'ARCHIVE ci-dessous
// Parameters : dcfYear, dcfMonth, dcfDay, dcfWeekDay
// Return value : weekNumber numéro de SEMAINE
//
//================================================================================================================
//Code from: http://forum.arduino.cc/index.php/topic,44476.0.html
int dayWeekNumber(int y, int m, int d, int w)
{
// Number of days at the beginning of the month in a normal (not leap) year.
int days[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
// Start to calculate the number of days of the first two months
if (m == 1 || m == 2)
{
// for any type of year we calculate the number of days for January or february
dayNumber = days[(m - 1)] + d;
}
// now calculate for the other months
// first, check for a leap year
else if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
{
// we have a leap year, so calculate in the same way but adding one day
dayNumber = days[(m - 1)] + d + 1;
}
else
{
//no leap year, calculate in the normal way, such as January or February
dayNumber = days[(m - 1)] + d;
}
// Now start to calculate Week number
if (w == 0)
{
//if it is sunday (time library returns 0)
weekNumber = (dayNumber - 7 + 10) / 7;
}
else
{
// for the other days of week
weekNumber = (dayNumber - w + 10) / 7;
}
// finished! return with the week number as an INT value
return weekNumber;
}
//================================================================================================================
//
// Function name : calculateLeapYear
// called from : <decodeBufferContents>
//
// Purpose : determine if a given year is a leap year
// Parameters : year - the year to test
// Return value : '1' if the year is a leap year, '0' otherwise
//
//================================================================================================================
int calculateLeapYear(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return 1;
}
else
{
return 0;
}
}
void decodeBufferContents(void)
{
// Buffer is full and ready to be decoded
dcfMinute = bitDecode(21, 27);
dcfHour = bitDecode(29, 34);
dcfDay = bitDecode(36, 41);
dcfWeekDay = bitDecode(42, 44);
dcfMonth = bitDecode(45, 49);
dcfYear = bitDecode(50, 57);
//call function to calculate day of year and weeknumber
dayWeekNumber(dcfYear, dcfMonth, dcfDay, dcfWeekDay);
// Get value of Summertime DCFbit. '1' = Summertime, '0' = wintertime
dcfDST = bitDecode(17, 17);
// determine Leap Year
leapYear = calculateLeapYear(dcfYear);
}
//================================================================================================================
//
// Function name : finalizeBuffer
// called from : <scanSignal>
//
// Purpose : Process the succesfully received DCF data of one minute
// Parameters : none
// Return value : none
//
//================================================================================================================
void finalizeBuffer(void)
{
//--------------------------------------------------------------------
// We are here because of the detected 2 second 'gap'.
// Now check if it correspondends with the buffer counter
// 'bufferPosition' which should be value 59
//--------------------------------------------------------------------
if (bufferPosition == 59 && dcfValidSignal == true)
{
// process buffer and extract data sync the time with the RTC
decodeBufferContents();
setTime(dcfHour, dcfMinute, 0, dcfDay, dcfMonth, dcfYear);
Serial.println();
Serial.print("Time: ");
Serial.print(dcfHour);
Serial.print(":");
Serial.print(dcfMinute);
Serial.println();
Serial.print("Date: ");
Serial.print(dcfDay);
Serial.print("-");
Serial.print(dcfMonth);
Serial.print("-");
Serial.print(dcfYear);
Serial.println();
// Reset running buffer
bufferPosition = 0;
// Reset DCFbitBuffer array, positions 0-58 (=59 bits)
for (int i = 0; i < 59; i++)
{
DCFbitBuffer = 0;
}
// reset flag
MinuteMarkerFlag = false;
} // if (bufferPosition == 59)
//--------------------------------------------------------------------
// The buffer is not yet filled although the 2 second 'gap' was detected.
// Can be result of a noisy signal, starting in middle of receiving data etc.
// Turn 'Minute Mark' LED ON
//--------------------------------------------------------------------
else
{
// Reset running buffer and start afresh. Now we are in sync with the incoming data
bufferPosition = 0;
// Reset DCFbitBuffer array, positions 0-58 (=59 bits)
for (int i = 0; i < 59; i++)
{
DCFbitBuffer = 0;
}
// set flag so we can display incoming pulsed on the inner LED ring.
MinuteMarkerFlag = true;
}
}
//================================================================================================================
//
// Function name : processDcfBit
// called from : <scanSignal>
//
// Purpose : Evaluates the signal as it is received. Decides whether we received a "1" or a "0"
// and perform checks to see if the pulse timing is within limits
// Parameters : none
// Return value : none
//
//================================================================================================================
/*
pulse pulse
width width
|- -| |-- --| |----- END OF MINUTE marker:2000ms -----|
___ _______ ___ ___ _______
| 0 | | 1 | | 0 | | 0 | | 1 |
| | | | | | | | | |
| | | | | | | | | |
______| |_______________| |___________| |___________________________________| |_______________| |__ _ _ _
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
1000 2100 2000 2200 3000 3100 NO PULSE 5000 5100 6000 6200 << example millis() value
= end of Minute indication
^ ^ ^ ^ ^
DCFbit# 56 DCFbit# 57 DCFbit# 58 DCFbit# 0 DCFbit# 1 etc... << DCF bit received
^ ^ ^
previous leading trailing
leading edge edge edge
^ ^
flanktime (rising or falling)
*/
void twoDigitPrint(int num) {
if (num == -1) {
Serial.print("??");
return;
}
if (num <= 9) {
Serial.print("0");
}
Serial.print(num);
}
void scanSignal()
{
//--------------------------------------------------------------------
// Check for Rising-Edge signal and perform checks
//--------------------------------------------------------------------
if (DCFSignalState == 1)
{
// store Rising-Edge Time to check later if the time between two pulses is valid
// stocker Rising-Edge Time pour vérifier plus tard si le temps entre deux impulsions est valide
leadingEdge = millis();
// not much to do now so exit.
return;
}
//--------------------------------------------------------------------
// Check for Falling-Edge signal and perform checks
//--------------------------------------------------------------------
if (DCFSignalState == 0)
{
// store Trailing-Edge Time to check later if the Pulse Width is valid
// stocker Trailing-Edge Time pour vérifier plus tard si la largeur d'impulsion est valide
trailingEdge = millis();
//--------------------------------------------------------------------------------
// Check PERIOD TIME
//--------------------------------------------------------------------------------
// If this flank UP is detected quickly after previous flank UP this is an incorrect
// Period Time (should be 1000ms -or 2000ms after second 58-) that we shall reject
if ((leadingEdge - previousLeadingEdge) < 900)
{
// rPW - ERROR: Periode Time (rising flank to rising flank) time is too short -> REJECTED
// rPW - ERREUR : le temps de période (flanc montant à flanc montant) est trop court -> REJETÉ
errorCondition = true;
}
//--------------------------------------------------------------------------------
// CHECK PULSE TIME
//--------------------------------------------------------------------------------
// If the detected pulse is too short it will be an incorrect pulse that we shall reject
// should be 100 and 200 ms ideally
Serial.print("trailingEdge - leadingEdge = "); Serial.println(trailingEdge - leadingEdge);
twoDigitPrint(hour());
Serial.print(":");
twoDigitPrint(minute());
Serial.print(":");
twoDigitPrint(second());
Serial.println();
Serial.print(day());
Serial.print("/");
Serial.print(month());
Serial.print("/");
Serial.println(year());
if (((trailingEdge - leadingEdge) < 70) || ((trailingEdge - leadingEdge) > 230))
{
//rPT - ERROR: Pulse Width too short or too long -> REJECTED
//rPT - ERREUR : Largeur d'impulsion trop courte ou trop longue -> REJETÉE
errorCondition = true;
}
// if we had an error return and start over
// si nous avons eu une erreur revenir et recommencer
if (errorCondition == true)
{
errorCondition = false;
// although we have an error, store current rising edge time to compare at the next Rising-Edge.
previousLeadingEdge = leadingEdge;
return;
}
//--------------------------------------------------------------------
// no errors found so now we can continue
//--------------------------------------------------------------------
// first we turn any error Led's OFF
// END OF MINUTE check, looking for a gap of approx. 2000ms
if (leadingEdge - previousLeadingEdge > 1900 && leadingEdge - previousLeadingEdge < 2100)
{
// end of minute detected:
// fin de minute détectée :
Serial.print("leadingEdge - previousLeadingEdge 2000ms= "); Serial.println(leadingEdge - previousLeadingEdge);
finalizeBuffer();
}
// refresh previousLeadingEdge time with the new leading edge time
previousLeadingEdge = leadingEdge;
//--------------------------------------------------------------------------------
// process DCF bits
//--------------------------------------------------------------------------------
// distinguish between long and short pulses
if (trailingEdge - leadingEdge < 170)
{
// call processDcfBit function and sent it the value '0'
processDcfBit(0);
}
else
{
// call processDcfBit function and sent it the value '1'
processDcfBit(1);
}
} // if (DCFSignalState == 0)
} // void scanSignal();
void initialize(void)
{
//---------------------------------------------------
// Initialize Variables
//---------------------------------------------------
leadingEdge = 0;
trailingEdge = 0;
previousLeadingEdge = 0;
bufferPosition = 0;
// Reset DCFbitBuffer array, positions 0-58 (=59 bits)
for (int i = 0; i < 59; i++)
{
DCFbitBuffer = 0;
}
}
//================================================================================================================
//
// Function name : tasksEverySecond
// called from : <loop>
//
// Purpose : perform tasks that must happen once every SECOND
// Parameters : none
// Return value : none
//
//================================================================================================================
void tasksEverySecond()
{
// check if time is changed
if (second() != previousSecond)
{
// 'reset' variable state
previousSecond = second();
//display the Real Time Clock Time
// displayRtcTime();
// display 'HI' and 'LO' temperature on specific moments
switch (second())
{
case 0:
// hourly chime output: ACTIVATE
break;
case 2:
// hourly chime output: DEACTIVATE
//digitalWrite(CHIMEPIN, LOW);
break;
case 30:
break;
case 31:
case 32:
// NOTE: I physically rotated digit 4 so when I activate the decimal dot, this now is the 'degrees dot' in the upper left corner
break;
case 33:
break;
case 34:
case 35:
break;
case 36:
// befor displaying the temperature in the next second,
break;
case 37:
// read temperature, store in min/max memory and display current temperature
// only once per minute this is done else things go wrong... ;)
break;
} // switch
} // (second() != previousSecond)
} // void tasksEverySecond()
//================================================================================================================
//
// Function name : int0handler
// called from :
//
// Purpose : when a rising or falling edge is detected on pin 2, this function is called
// Parameters : none
// Return value : none
//
//================================================================================================================
void int0handler()
{
DCFSignalState = digitalRead(DCF77PIN);
}
void loop() {
// check first if pulse direction is changed (rising or falling)
// else we would keep evaluating the same pulse
if (DCFSignalState != previousSignalState)
{
// 'reset' state of variable
previousSignalState = DCFSignalState;
// evaluate incoming pulse
scanSignal();
}
}
j'ai utiliser celui la aussi
#include <TimeLib.h>
#define READPIN 2
#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 //2100L 2.1 secondes (= 2100 millisecondes)
#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
};
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.println();
Serial.print("Complete OK: ");
Serial.print(dcf_hours);
Serial.print(":");
Serial.print(dcf_mins);
Serial.println(" ");
Serial.print(dcf_day);
Serial.print("-");
Serial.print(dcf_month);
Serial.print("-");
Serial.print(dcf_year);
Serial.println();
// set the current time to 14:27:00, December 14th, 2015
//setTime(14, 27, 00, 14, 12, 2015);
setTime(dcf_hours, dcf_mins, 0, dcf_day, dcf_month, dcf_year);
Serial.println("date et heure mise à jour");
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
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.println();
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.println();
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);
pinMode(LED_BUILTIN, OUTPUT);
}
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;
}
// Serial.clear();
if (showTime)
{
if (dcf_received_time==true &&& dcf_received_date!=true)
{
Serial.println();
twoDigitPrint(hour());
Serial.print(":");
twoDigitPrint(minute());
Serial.print(":");
twoDigitPrint(second());
Serial.println();
Serial.print(day());
Serial.print("-");
Serial.print(month());
Serial.print("-");
Serial.print(year());
} else {
Serial.println();
Serial.print("Waiting ");
Serial.print(millis() / 1000);
Serial.print(" sec");
}
} else {
Serial.println();
Serial.print("DCF ");
twoDigitPrint(last_dcf_hours);
Serial.print(":");
twoDigitPrint(last_dcf_mins);
Serial.print(" (");
Serial.print(((millis() - last_dcf_received) / 1000));
Serial.print(")");
Serial.println();
oneDigitPrint(last_dcf_day);
Serial.print("-");
oneDigitPrint(last_dcf_month);
Serial.print("-");
oneDigitPrint(last_dcf_year);
}
lastRef = millis();
}
}
void oneDigitPrint(int num) {
if (num == -1) {
Serial.print("??");
return;
}
Serial.print(num);
}
void twoDigitPrint(int num) {
if (num == -1) {
Serial.print("??");
return;
}
if (num <= 9) {
Serial.print("0");
}
Serial.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();
// if ( dcf_received_date != true && dcf_received_time!= true)
// {
boolean active = digitalRead(READPIN);
if (active)
{
while (true)
{
active = digitalRead(READPIN);
if (active)
{
stopTime = millis();
}
else
{
if (millis() < stopTime)
{
Serial.println("transition entre 2 minutes, impulsion pendant 2 secondes.");
//arduino time wrap-around, break loop bouclage du temps arduino, boucle de rupture
break;
}
tmp = millis() - stopTime;
if ( tmp > 2L) ////2000L 2 secondes (= 2000 millisecondes) La transition entre 2 minutes est manifestée par l'absence d'impulsion pour le bit 59 : on a donc une absence d'impulsion pendant 2 secondes.
{
break;// break est utilisé pour sortir d'une boucle for,while,do...while, en contournant la condition de boucle normale. Il est également utilisé pour sortir d'un switch case
}
}//fin else if (active)
}//fin 2eme while (true)
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) {
Serial.println();
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) {
Serial.println();
debugPrint("REJ: ", startTime, elapsed);
}
}
if (signalGap >= SIGNALGAP_DUR_START && signalGap <= SIGNALGAP_DUR_END) {
if (DEBUG) {
Serial.println();
debugPrint("GAP: ", startTime, elapsed);
}
analyseSignal(i, bits, sTimes);
}
}// fin if (active)
}// fin premier while(true)
// }//
}// fin loop
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 = -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) {
// wait for a second
digitalWrite(LED_BUILTIN, LOW);
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);
}
}// fin analyseSignal
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;
} //fin checkEvenParity
void debugPrint(String prefix, unsigned long time, unsigned long elapsed)
{
Serial.print(prefix);
Serial.print(time);
Serial.print(" - ");
Serial.print(elapsed);
Serial.println();
} // fin debugPrint
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();
}// fin debugSignal
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;
}// fin getValue
ca fonctionne mais de gros probleme pour la reception
ca fonctionne pas tous les jours j'avais utilise ce code arduino nano
#include <TimeLib.h>
#define DCF77PIN 2 // input - DCF signal from antenna pcb. Pin must an interrupt input!
#define DCF_INTERRUPT 0 // Interrupt number associated with pin
#define LED_LEAPYEAR 31 // output - LED - Leap year
#define LED_DCFSTATUS 42 // output - LED - On when we have good DCF data
// Pulse flanks
static unsigned long leadingEdge = 0;
static unsigned long trailingEdge = 0;
unsigned long previousLeadingEdge = 0;
int bufferPosition = 0;
// used in <Int0handler>
volatile unsigned int DCFSignalState = 0; // interrupt variables ALWAYS need volatile qualifier!!
boolean errorCondition = false;
// used in <loop>
int previousSecond = 0;
unsigned int previousSignalState = 0;
// DCF Buffers and indicators
static int DCFbitBuffer[59]; // here, the received DCFbits are stored
const int bitValue[] = {1, 2, 4, 8, 10, 20, 40, 80}; // these are the decimal values of the received DCFbits
// dcf variables to store decoded DCF time in
int dcfMinute = 0;
int dcfHour = 0;
int dcfDay = 0;
int dcfWeekDay = 0;
int dcfMonth = 0;
int dcfYear = 0;
int dcfDST = 0;
int leapYear = 0;
// variables to check if DCF bits are valid
bool dcfValidSignal = false;
int dcfP1counter = 0;
int dcfP2counter = 0;
int dcfP3counter = 0;
int dcfParityCheckP1 = 0;
int dcfParityCheckP2 = 0;
int dcfParityCheckP3 = 0;
// variables used to store weeknumber and daynumber values
int dayNumber;
int weekNumber;
// only after start on a new minute, display received bits on inner LED ring
boolean MinuteMarkerFlag = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(DCF77PIN, INPUT);
initialize();
attachInterrupt(DCF_INTERRUPT, int0handler, CHANGE);
}
//================================================================================================================
//
// Function name : processDcfBit
// called from : <scanSignal>
//
// Purpose : after reception of one good DCF bit, do some checks and save it in the DCFbitBuffer array
// Parameters : none
// Return value : none
//
//================================================================================================================
void processDcfBit(int dcfBit)
{
//--------------------------------------------------------------------
// display incoming DCF bits on inner LED ring
//--------------------------------------------------------------------
// only if we have valid DCF data or after an Minute Mark (EoM) signal
//--------------------------------------------------------------------
// // Fill DCFbitBuffer array with DCFbit
//--------------------------------------------------------------------
DCFbitBuffer[bufferPosition] = dcfBit;
//--------------------------------------------------------------------
// Parity check
//--------------------------------------------------------------------
// DURING reception of the DCF bits, calculate and display the results of the DCF parity check.
//
// There is a Parity bit for the minutes, the hours and for the date.
// DCF77 works with EVEN parity, this works as follows:
// The hours for example have 6 bits plus a paritybit. The bits with value 1 are add up including the paritybit,
// the result must be an even number. If there is a bit wrong received, a 0 is as 1, or a 1 is as 0 received,
// then the result is uneven. source: http://www.picbasic.nl/frameload_uk.htm?http://www.picbasic.nl/info_dcf77_uk.htm
if (bufferPosition == 0)
{
// reset variables
dcfP1counter = 0;
dcfP2counter = 0;
dcfP3counter = 0;
dcfParityCheckP1 = 0;
dcfParityCheckP2 = 0;
dcfParityCheckP3 = 0;
}
// ----------------------------------------
// First parity check: minute bits
// ----------------------------------------
if (bufferPosition == 28)
{
for (int i = 21; i <= 27; i++)
{
// count the number of bits with the value '1'
dcfP1counter += DCFbitBuffer;
}
// perform P1 parity check. Parity is OK if the sum is an EVEN value
if ((DCFbitBuffer[28] + dcfP1counter) % 2 == 0)
{
// Parity P1 PASS
dcfParityCheckP1 = 1;
}
else
{
// we have no valid data!
dcfValidSignal = false;
}
}
// ----------------------------------------
// Second parity check: hour bits
// ----------------------------------------
if (bufferPosition == 35)
{
for (int i = 29; i <= 34; i++)
{
dcfP2counter += DCFbitBuffer;
}
// perform P2 parity check. Parity is OK if the sum is an EVEN value
if ((DCFbitBuffer[35] + dcfP2counter) % 2 == 0)
{
// Parity P2 PASS
dcfParityCheckP2 = 1;
}
else
{
// we have no valid data!
dcfValidSignal = false;
}
}
// ----------------------------------------
// Third parity check: date bits
// ----------------------------------------
if (bufferPosition == 58)
{
for (int i = 36; i <= 57; i++)
{
dcfP3counter += DCFbitBuffer;
}
// perform P3 parity check. Parity is OK if the sum is an EVEN value
(DCFbitBuffer[58] + dcfP3counter) % 2 == 0 ? dcfParityCheckP3 = 1 : dcfParityCheckP3 = 0;
// Turn Parity2 'PASS' or 'FAIL' LED ON
if (dcfParityCheckP3 == 1)
{
// Parity P3 PASS
dcfParityCheckP3 = 1;
}
else
{
// we have no valid data!
dcfValidSignal = false;
// Turn DCF OK LED OFF
}
// ----------------------------------------
// finally, check all Parity bits
// ----------------------------------------
dcfParityCheckP1 + dcfParityCheckP2 + dcfParityCheckP3 == 3 ? dcfValidSignal = true : dcfValidSignal = false;
}
//--------------------------------------------------------------------
// before continuing with the next bit, increment counter
//--------------------------------------------------------------------
bufferPosition++;
//--------------------------------------------------------------------
// check if we have not received too many pulses?
//--------------------------------------------------------------------
if (bufferPosition > 59)
{
// Buffer Overflow ERROR - we have received more pulses before reaching
// the 2 second 'gap' signalling the end of the minute.
//This error may be due to a noisy signal giving addition peaks/dcfBits
// So clear both DCFbit displays and start again.
// Buffer Overflow ERROR - nous avons reçu plus d'impulsions avant d'atteindre
// le 'gap' de 2 secondes signalant la fin de la minute.
//Cette erreur peut être due à un signal bruité donnant des pics d'addition/dcfBits
// Donc, effacez les deux affichages DCFbit et recommencez.
// Reset buffer counter
bufferPosition = 0;
// turn Buffer Overflow Error LED ON
// exit
return;
}
//--------------------------------------------------------------------
// everything OK so we wait for next incoming DCFbit
// tout va bien donc nous attendons le prochain DCFbit entrant
//--------------------------------------------------------------------
}
//================================================================================================================
//
// bitDecode
//
// called from <processBuffer>
//================================================================================================================
int bitDecode(int bitStart, int bitEnd)
{
// reset 'bitValue-array' counter
int i = 0;
int value = 0;
// process bitrange bitStart > bitEnd
while (bitStart <= bitEnd)
{
// check if DCFbit in buffer is '1', discard when '0'
if (DCFbitBuffer[bitStart] == 1)
{
// DCFbit in buffer == 1 so append its corresponding value to the variable 'value'
// DCFbit in buffer == 1 donc ajouter sa valeur correspondante à la variable 'value'
value = value + bitValue;
}
// increment 'bitValue-array' counter
i++;
// increment bit-range counter
bitStart++;
}
return value;
}
//================================================================================================================
//
// Function name : dayWeekNumber
// called from : <decodeBufferContents>
//
// Purpose : calculate the WEEK number according to ISO standard, see comments in the ARCHIVE below
// calculer le numéro de SEMAINE selon la norme ISO, voir les commentaires dans l'ARCHIVE ci-dessous
// Parameters : dcfYear, dcfMonth, dcfDay, dcfWeekDay
// Return value : weekNumber numéro de SEMAINE
//
//================================================================================================================
//Code from: http://forum.arduino.cc/index.php/topic,44476.0.html
int dayWeekNumber(int y, int m, int d, int w)
{
// Number of days at the beginning of the month in a normal (not leap) year.
int days[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
// Start to calculate the number of days of the first two months
if (m == 1 || m == 2)
{
// for any type of year we calculate the number of days for January or february
dayNumber = days[(m - 1)] + d;
}
// now calculate for the other months
// first, check for a leap year
else if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
{
// we have a leap year, so calculate in the same way but adding one day
dayNumber = days[(m - 1)] + d + 1;
}
else
{
//no leap year, calculate in the normal way, such as January or February
dayNumber = days[(m - 1)] + d;
}
// Now start to calculate Week number
if (w == 0)
{
//if it is sunday (time library returns 0)
weekNumber = (dayNumber - 7 + 10) / 7;
}
else
{
// for the other days of week
weekNumber = (dayNumber - w + 10) / 7;
}
// finished! return with the week number as an INT value
return weekNumber;
}
//================================================================================================================
//
// Function name : calculateLeapYear
// called from : <decodeBufferContents>
//
// Purpose : determine if a given year is a leap year
// Parameters : year - the year to test
// Return value : '1' if the year is a leap year, '0' otherwise
//
//================================================================================================================
int calculateLeapYear(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
return 1;
}
else
{
return 0;
}
}
void decodeBufferContents(void)
{
// Buffer is full and ready to be decoded
dcfMinute = bitDecode(21, 27);
dcfHour = bitDecode(29, 34);
dcfDay = bitDecode(36, 41);
dcfWeekDay = bitDecode(42, 44);
dcfMonth = bitDecode(45, 49);
dcfYear = bitDecode(50, 57);
//call function to calculate day of year and weeknumber
dayWeekNumber(dcfYear, dcfMonth, dcfDay, dcfWeekDay);
// Get value of Summertime DCFbit. '1' = Summertime, '0' = wintertime
dcfDST = bitDecode(17, 17);
// determine Leap Year
leapYear = calculateLeapYear(dcfYear);
}
//================================================================================================================
//
// Function name : finalizeBuffer
// called from : <scanSignal>
//
// Purpose : Process the succesfully received DCF data of one minute
// Parameters : none
// Return value : none
//
//================================================================================================================
void finalizeBuffer(void)
{
//--------------------------------------------------------------------
// We are here because of the detected 2 second 'gap'.
// Now check if it correspondends with the buffer counter
// 'bufferPosition' which should be value 59
//--------------------------------------------------------------------
if (bufferPosition == 59 && dcfValidSignal == true)
{
// process buffer and extract data sync the time with the RTC
decodeBufferContents();
setTime(dcfHour, dcfMinute, 0, dcfDay, dcfMonth, dcfYear);
Serial.println();
Serial.print("Time: ");
Serial.print(dcfHour);
Serial.print(":");
Serial.print(dcfMinute);
Serial.println();
Serial.print("Date: ");
Serial.print(dcfDay);
Serial.print("-");
Serial.print(dcfMonth);
Serial.print("-");
Serial.print(dcfYear);
Serial.println();
// Reset running buffer
bufferPosition = 0;
// Reset DCFbitBuffer array, positions 0-58 (=59 bits)
for (int i = 0; i < 59; i++)
{
DCFbitBuffer = 0;
}
// reset flag
MinuteMarkerFlag = false;
} // if (bufferPosition == 59)
//--------------------------------------------------------------------
// The buffer is not yet filled although the 2 second 'gap' was detected.
// Can be result of a noisy signal, starting in middle of receiving data etc.
// Turn 'Minute Mark' LED ON
//--------------------------------------------------------------------
else
{
// Reset running buffer and start afresh. Now we are in sync with the incoming data
bufferPosition = 0;
// Reset DCFbitBuffer array, positions 0-58 (=59 bits)
for (int i = 0; i < 59; i++)
{
DCFbitBuffer = 0;
}
// set flag so we can display incoming pulsed on the inner LED ring.
MinuteMarkerFlag = true;
}
}
//================================================================================================================
//
// Function name : processDcfBit
// called from : <scanSignal>
//
// Purpose : Evaluates the signal as it is received. Decides whether we received a "1" or a "0"
// and perform checks to see if the pulse timing is within limits
// Parameters : none
// Return value : none
//
//================================================================================================================
/*
pulse pulse
width width
|- -| |-- --| |----- END OF MINUTE marker:2000ms -----|
___ _______ ___ ___ _______
| 0 | | 1 | | 0 | | 0 | | 1 |
| | | | | | | | | |
| | | | | | | | | |
______| |_______________| |___________| |___________________________________| |_______________| |__ _ _ _
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
1000 2100 2000 2200 3000 3100 NO PULSE 5000 5100 6000 6200 << example millis() value
= end of Minute indication
^ ^ ^ ^ ^
DCFbit# 56 DCFbit# 57 DCFbit# 58 DCFbit# 0 DCFbit# 1 etc... << DCF bit received
^ ^ ^
previous leading trailing
leading edge edge edge
^ ^
flanktime (rising or falling)
*/
void twoDigitPrint(int num) {
if (num == -1) {
Serial.print("??");
return;
}
if (num <= 9) {
Serial.print("0");
}
Serial.print(num);
}
void scanSignal()
{
//--------------------------------------------------------------------
// Check for Rising-Edge signal and perform checks
//--------------------------------------------------------------------
if (DCFSignalState == 1)
{
// store Rising-Edge Time to check later if the time between two pulses is valid
// stocker Rising-Edge Time pour vérifier plus tard si le temps entre deux impulsions est valide
leadingEdge = millis();
// not much to do now so exit.
return;
}
//--------------------------------------------------------------------
// Check for Falling-Edge signal and perform checks
//--------------------------------------------------------------------
if (DCFSignalState == 0)
{
// store Trailing-Edge Time to check later if the Pulse Width is valid
// stocker Trailing-Edge Time pour vérifier plus tard si la largeur d'impulsion est valide
trailingEdge = millis();
//--------------------------------------------------------------------------------
// Check PERIOD TIME
//--------------------------------------------------------------------------------
// If this flank UP is detected quickly after previous flank UP this is an incorrect
// Period Time (should be 1000ms -or 2000ms after second 58-) that we shall reject
if ((leadingEdge - previousLeadingEdge) < 900)
{
// rPW - ERROR: Periode Time (rising flank to rising flank) time is too short -> REJECTED
// rPW - ERREUR : le temps de période (flanc montant à flanc montant) est trop court -> REJETÉ
errorCondition = true;
}
//--------------------------------------------------------------------------------
// CHECK PULSE TIME
//--------------------------------------------------------------------------------
// If the detected pulse is too short it will be an incorrect pulse that we shall reject
// should be 100 and 200 ms ideally
Serial.print("trailingEdge - leadingEdge = "); Serial.println(trailingEdge - leadingEdge);
twoDigitPrint(hour());
Serial.print(":");
twoDigitPrint(minute());
Serial.print(":");
twoDigitPrint(second());
Serial.println();
Serial.print(day());
Serial.print("/");
Serial.print(month());
Serial.print("/");
Serial.println(year());
if (((trailingEdge - leadingEdge) < 70) || ((trailingEdge - leadingEdge) > 230))
{
//rPT - ERROR: Pulse Width too short or too long -> REJECTED
//rPT - ERREUR : Largeur d'impulsion trop courte ou trop longue -> REJETÉE
errorCondition = true;
}
// if we had an error return and start over
// si nous avons eu une erreur revenir et recommencer
if (errorCondition == true)
{
errorCondition = false;
// although we have an error, store current rising edge time to compare at the next Rising-Edge.
previousLeadingEdge = leadingEdge;
return;
}
//--------------------------------------------------------------------
// no errors found so now we can continue
//--------------------------------------------------------------------
// first we turn any error Led's OFF
// END OF MINUTE check, looking for a gap of approx. 2000ms
if (leadingEdge - previousLeadingEdge > 1900 && leadingEdge - previousLeadingEdge < 2100)
{
// end of minute detected:
// fin de minute détectée :
Serial.print("leadingEdge - previousLeadingEdge 2000ms= "); Serial.println(leadingEdge - previousLeadingEdge);
finalizeBuffer();
}
// refresh previousLeadingEdge time with the new leading edge time
previousLeadingEdge = leadingEdge;
//--------------------------------------------------------------------------------
// process DCF bits
//--------------------------------------------------------------------------------
// distinguish between long and short pulses
if (trailingEdge - leadingEdge < 170)
{
// call processDcfBit function and sent it the value '0'
processDcfBit(0);
}
else
{
// call processDcfBit function and sent it the value '1'
processDcfBit(1);
}
} // if (DCFSignalState == 0)
} // void scanSignal();
void initialize(void)
{
//---------------------------------------------------
// Initialize Variables
//---------------------------------------------------
leadingEdge = 0;
trailingEdge = 0;
previousLeadingEdge = 0;
bufferPosition = 0;
// Reset DCFbitBuffer array, positions 0-58 (=59 bits)
for (int i = 0; i < 59; i++)
{
DCFbitBuffer = 0;
}
}
//================================================================================================================
//
// Function name : tasksEverySecond
// called from : <loop>
//
// Purpose : perform tasks that must happen once every SECOND
// Parameters : none
// Return value : none
//
//================================================================================================================
void tasksEverySecond()
{
// check if time is changed
if (second() != previousSecond)
{
// 'reset' variable state
previousSecond = second();
//display the Real Time Clock Time
// displayRtcTime();
// display 'HI' and 'LO' temperature on specific moments
switch (second())
{
case 0:
// hourly chime output: ACTIVATE
break;
case 2:
// hourly chime output: DEACTIVATE
//digitalWrite(CHIMEPIN, LOW);
break;
case 30:
break;
case 31:
case 32:
// NOTE: I physically rotated digit 4 so when I activate the decimal dot, this now is the 'degrees dot' in the upper left corner
break;
case 33:
break;
case 34:
case 35:
break;
case 36:
// befor displaying the temperature in the next second,
break;
case 37:
// read temperature, store in min/max memory and display current temperature
// only once per minute this is done else things go wrong... ;)
break;
} // switch
} // (second() != previousSecond)
} // void tasksEverySecond()
//================================================================================================================
//
// Function name : int0handler
// called from :
//
// Purpose : when a rising or falling edge is detected on pin 2, this function is called
// Parameters : none
// Return value : none
//
//================================================================================================================
void int0handler()
{
DCFSignalState = digitalRead(DCF77PIN);
}
void loop() {
// check first if pulse direction is changed (rising or falling)
// else we would keep evaluating the same pulse
if (DCFSignalState != previousSignalState)
{
// 'reset' state of variable
previousSignalState = DCFSignalState;
// evaluate incoming pulse
scanSignal();
}
}
j'ai utiliser celui la aussi
#include <TimeLib.h>
#define READPIN 2
#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 //2100L 2.1 secondes (= 2100 millisecondes)
#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
};
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.println();
Serial.print("Complete OK: ");
Serial.print(dcf_hours);
Serial.print(":");
Serial.print(dcf_mins);
Serial.println(" ");
Serial.print(dcf_day);
Serial.print("-");
Serial.print(dcf_month);
Serial.print("-");
Serial.print(dcf_year);
Serial.println();
// set the current time to 14:27:00, December 14th, 2015
//setTime(14, 27, 00, 14, 12, 2015);
setTime(dcf_hours, dcf_mins, 0, dcf_day, dcf_month, dcf_year);
Serial.println("date et heure mise à jour");
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
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.println();
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.println();
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);
pinMode(LED_BUILTIN, OUTPUT);
}
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;
}
// Serial.clear();
if (showTime)
{
if (dcf_received_time==true &&& dcf_received_date!=true)
{
Serial.println();
twoDigitPrint(hour());
Serial.print(":");
twoDigitPrint(minute());
Serial.print(":");
twoDigitPrint(second());
Serial.println();
Serial.print(day());
Serial.print("-");
Serial.print(month());
Serial.print("-");
Serial.print(year());
} else {
Serial.println();
Serial.print("Waiting ");
Serial.print(millis() / 1000);
Serial.print(" sec");
}
} else {
Serial.println();
Serial.print("DCF ");
twoDigitPrint(last_dcf_hours);
Serial.print(":");
twoDigitPrint(last_dcf_mins);
Serial.print(" (");
Serial.print(((millis() - last_dcf_received) / 1000));
Serial.print(")");
Serial.println();
oneDigitPrint(last_dcf_day);
Serial.print("-");
oneDigitPrint(last_dcf_month);
Serial.print("-");
oneDigitPrint(last_dcf_year);
}
lastRef = millis();
}
}
void oneDigitPrint(int num) {
if (num == -1) {
Serial.print("??");
return;
}
Serial.print(num);
}
void twoDigitPrint(int num) {
if (num == -1) {
Serial.print("??");
return;
}
if (num <= 9) {
Serial.print("0");
}
Serial.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();
// if ( dcf_received_date != true && dcf_received_time!= true)
// {
boolean active = digitalRead(READPIN);
if (active)
{
while (true)
{
active = digitalRead(READPIN);
if (active)
{
stopTime = millis();
}
else
{
if (millis() < stopTime)
{
Serial.println("transition entre 2 minutes, impulsion pendant 2 secondes.");
//arduino time wrap-around, break loop bouclage du temps arduino, boucle de rupture
break;
}
tmp = millis() - stopTime;
if ( tmp > 2L) ////2000L 2 secondes (= 2000 millisecondes) La transition entre 2 minutes est manifestée par l'absence d'impulsion pour le bit 59 : on a donc une absence d'impulsion pendant 2 secondes.
{
break;// break est utilisé pour sortir d'une boucle for,while,do...while, en contournant la condition de boucle normale. Il est également utilisé pour sortir d'un switch case
}
}//fin else if (active)
}//fin 2eme while (true)
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) {
Serial.println();
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) {
Serial.println();
debugPrint("REJ: ", startTime, elapsed);
}
}
if (signalGap >= SIGNALGAP_DUR_START && signalGap <= SIGNALGAP_DUR_END) {
if (DEBUG) {
Serial.println();
debugPrint("GAP: ", startTime, elapsed);
}
analyseSignal(i, bits, sTimes);
}
}// fin if (active)
}// fin premier while(true)
// }//
}// fin loop
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 = -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) {
// wait for a second
digitalWrite(LED_BUILTIN, LOW);
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);
}
}// fin analyseSignal
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;
} //fin checkEvenParity
void debugPrint(String prefix, unsigned long time, unsigned long elapsed)
{
Serial.print(prefix);
Serial.print(time);
Serial.print(" - ");
Serial.print(elapsed);
Serial.println();
} // fin debugPrint
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();
}// fin debugSignal
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;
}// fin getValue