Hi, So i making clock based on DS3231 module able to adjust time with DCF77 signal. Everything seems to work like it should. BUT. When i try to adjust RTC by decoded DCF77 signal all hangs up. I'm strugling to find whats wrong in the code. Looking for assist.
P.S. If i use RTC based on millis (RTC_Millis rtc;) everething works as intend.
#include <util/parity.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
int interruptPin = 2;
int ledPin = 7; // LED to monitor DCF77 signal
volatile unsigned long lastInt = 0;
volatile unsigned long long currentBuf = 0;
volatile byte bufCounter;
RTC_DS3231 rtc;
DateTime lastSyncTime; // Variable to store the last sync time
// LCD I2C address
LiquidCrystal_I2C lcd(0x27, 20, 4);
bool timeSynced = false; // Flag to track if the time is synced
void setup() {
// Start I2C communication
Wire.begin();
// Initialize the DS3231 RTC
if (!rtc.begin()) {
lcd.setCursor(0, 0);
lcd.print("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
lcd.setCursor(0, 1);
lcd.print("RTC lost power");
// Set the RTC to the current date and time
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
pinMode(interruptPin, INPUT);
pinMode(ledPin, OUTPUT); // Set LED pin as output
digitalWrite(ledPin, LOW); // Turn off LED initially
// Initialize the LCD
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.clear();
// Set up interrupt for DCF77 signal
attachInterrupt(digitalPinToInterrupt(interruptPin), DCF77_ISR, CHANGE);
}
void loop() {
DateTime now = rtc.now();
// Adjust for UTC +2
now = DateTime(now.year(), now.month(), now.day(), now.hour() + 1, now.minute(), now.second());
// Check if DST is active
bool dstActive = isDST(now);
// Adjust the time if DST is active (e.g., add 1 hour)
if (dstActive) {
now = DateTime(now.year(), now.month(), now.day(), now.hour() +1, now.minute(), now.second());
}
// Update the LCD display based on time sync status
lcd.setCursor(0, 0);
if (timeSynced) {
lcd.print("Time Synced");
} else {
lcd.print("Time Not Synced");
}
// Print date (Day-Month-Year) on the first row
lcd.setCursor(0, 1);
lcd.print("Date: ");
if (now.day() < 10) lcd.print('0'); // Add leading zero for day
lcd.print(now.day());
lcd.print('-');
if (now.month() < 10) lcd.print('0'); // Add leading zero for month
lcd.print(now.month());
lcd.print('-');
lcd.print(now.year());
// Print time (Hour:Minute:Second) on the second row
lcd.setCursor(0, 2);
lcd.print("Time: ");
if (now.hour() < 10) lcd.print('0'); // Add leading zero for hour
lcd.print(now.hour());
lcd.print(':');
if (now.minute() < 10) lcd.print('0'); // Add leading zero for minute
lcd.print(now.minute());
lcd.print(':');
if (now.second() < 10) lcd.print('0'); // Add leading zero for second
lcd.print(now.second());
// Print the day of the week on the third row
lcd.setCursor(0, 3);
lcd.print("Day: ");
String dayOfWeek = dayOfWeekToString(now.dayOfTheWeek());
lcd.print(dayOfWeek);
delay(1000); // Update every 1 second
}
// Interrupt service routine for DCF77 signal
void DCF77_ISR() {
unsigned int dur = 0;
dur = millis() - lastInt;
if (digitalRead(interruptPin)) {
digitalWrite(ledPin, HIGH); // Turn on LED when signal is HIGH
if (dur > 1500) {
if (bufCounter == 59) {
evaluateSequence();
}
bufCounter = 0;
currentBuf = 0;
}
} else {
digitalWrite(ledPin, LOW); // Turn off LED when signal is LOW
if (dur > 150) {
currentBuf |= ((unsigned long long)1 << bufCounter);
}
bufCounter++;
}
lastInt = millis();
}
// Evaluate the received DCF77 signal
void evaluateSequence() {
byte dcf77Year = (currentBuf >> 50) & 0xFF; // year = bit 50-57
byte dcf77Month = (currentBuf >> 45) & 0x1F; // month = bit 45-49
byte dcf77DayOfWeek = (currentBuf >> 42) & 0x07; // day of the week = bit 42-44
byte dcf77DayOfMonth = (currentBuf >> 36) & 0x3F; // day of the month = bit 36-41
byte dcf77Hour = (currentBuf >> 29) & 0x3F; // hour = bit 29-34
byte dcf77Minute = (currentBuf >> 21) & 0x7F; // minute = 21-27
bool parityBitMinute = (currentBuf >> 28) & 1;
bool parityBitHour = (currentBuf >> 35) & 1;
bool parityBitDate = (currentBuf >> 58) & 1;
if ((parity_even_bit(dcf77Minute)) == parityBitMinute) {
if ((parity_even_bit(dcf77Hour)) == parityBitHour) {
if (((parity_even_bit(dcf77DayOfMonth) + parity_even_bit(dcf77DayOfWeek)
+ parity_even_bit(dcf77Month) + parity_even_bit(dcf77Year)) % 2) == parityBitDate) {
rtc.adjust(DateTime(rawByteToInt(dcf77Year) + 2000, rawByteToInt(dcf77Month),
rawByteToInt(dcf77DayOfMonth), rawByteToInt(dcf77Hour), rawByteToInt(dcf77Minute), 0));
timeSynced = true; // Mark time as synced
}
}
}
}
// Convert raw DCF77 byte to integer
unsigned int rawByteToInt(byte raw) {
return ((raw >> 4) * 10 + (raw & 0x0F));
}
// Convert day of the week number to string
String dayOfWeekToString(int day) {
switch (day) {
case 0: return "Sun";
case 1: return "Mon";
case 2: return "Tue";
case 3: return "Wed";
case 4: return "Thu";
case 5: return "Fri";
case 6: return "Sat";
default: return "Invalid";
}
}
// Check if DST is active
bool isDST(DateTime now) {
int month = now.month();
int day = now.day();
if (month < 3 || month > 10) { // Outside the DST months (March-October)
return false;
}
// Check for the last Sunday of March
if (month == 3) {
int weekday = now.dayOfTheWeek();
if (day >= 25 && weekday == 0) { // If it's the last Sunday of March
return true;
}
}
// Check for the last Sunday of October
if (month == 10) {
int weekday = now.dayOfTheWeek();
if (day >= 25 && weekday == 0) { // If it's the last Sunday of October
return false;
}
}
return true; // Between the last Sunday of March and the last Sunday of October, DST is active
}