Some time ago I created a digital clock project using an LCD display and an RTC module (The DS1307). I decided to upgrade it by adding a DCF77 receiver and a better RTC module (The DS3231).
Following this forum page I saw that someone had already managed to create a code that allowed updating the RTC module after receiving a "Time telegraph" from the DCF77 receiver.
However, this code does not use the weekday, which is what I used in my previous code
(Here is the code for my Arduino + DS1307 version. I had set a day of the week slideshow every 15 seconds.)
#define D5 5
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2);
char daysOfTheWeek[7][12] = {"Domenica.", "Lunedi.", "Martedi.", "Mercoledi.", "Giovedi.", "Venerdi!!!", "Sabato."}; //va da 1 a 7 e ritorna a 1. Domenica è 1.
void setup ()
{
Serial.begin(9600);
lcd.init();
lcd.backlight();//To Power ON the back light
pinMode (D5, OUTPUT);
analogWrite(D5, 50);
if (! rtc.begin())
{
lcd.print("Couldn't find RTC");
while (1);
}
if (! rtc.isrunning())
{
lcd.print("RTC is NOT running!");
}
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));//auto update from computer time
//rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));// to set the time manually
}
void loop() {
DateTime now = rtc.now();
//slide-show del giorno della settimana
if((now.second()%15) == 0) {
lcd.clear();
lcd.setCursor(4,0);
lcd.print("Oggi e':");
lcd.setCursor(4,1);
lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
delay(4000);
lcd.clear();
}
else {
//Mostra semplicemente la data e l'ora:
lcd.setCursor(0,0); //prima colonna, prima riga.
lcd.print("Ora:");
if(now.hour() < 10) {
lcd.setCursor(8,0);
lcd.print("0");
lcd.setCursor(9,0);
lcd.print(now.hour());
}
else {
lcd.setCursor(8,0);
lcd.print(now.hour());
}
lcd.setCursor(10,0);
lcd.print(':');
if(now.minute() < 10) {
lcd.setCursor(11,0);
lcd.print("0");
lcd.setCursor(12,0);
lcd.print(now.minute());
}
else {
lcd.setCursor(11,0);
lcd.print(now.minute());
}
lcd.setCursor(13,0);
lcd.print(':');
if (now.second() < 10) {
lcd.setCursor(14,0);
lcd.print("0");
lcd.setCursor(15,0);
lcd.print(now.second());
}
else {
lcd.setCursor(14,0);
lcd.print(now.second());
}
//DATA
lcd.setCursor(0,1);
lcd.print("Data:");
if(now.day() < 10) {
lcd.setCursor(6,1);
lcd.print("0");
lcd.setCursor(7,1);
lcd.print(now.day());
}
else {
lcd.setCursor(6,1);
lcd.print(now.day());
}
lcd.setCursor(8,1);
lcd.print('/');
if(now.month() < 10) {
lcd.setCursor(9,1);
lcd.print("0");
lcd.setCursor(10,1);
lcd.print(now.month());
}
else {
lcd.setCursor(9,1);
lcd.print(now.month());
}
lcd.setCursor(11,1);
lcd.print('/');
lcd.setCursor(12,1);
lcd.print(now.year());
}
}
(Here, however, you can see how the creator of the code found online for the Arduino + DS3231 + DCF77receiver project does not foresee the use of the day of the week in two parts. The reference file is "jursDCFtime.h".)
First part:
void RTCreadTime(sTime &time)
// read current time from RTC
{
// Reset the register pointer
Wire.beginTransmission(RTC_I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(RTC_I2C_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
time.bSecond= bcdToDec(Wire.read() & 0x7f);
time.bMinute= bcdToDec(Wire.read());
time.bHour = bcdToDec(Wire.read() & 0x3f); // Need to change this if 12 hour am/pm
bcdToDec(Wire.read()); // day of week not used
time.bDay = bcdToDec(Wire.read());
time.bMonth = bcdToDec(Wire.read());
time.iYear = bcdToDec(Wire.read())+2000;
}
Second part:
void RTCwriteTime(sTime time)
// write time to RTC
{
Wire.beginTransmission(RTC_I2C_ADDRESS);
Wire.write(0);
Wire.write(decToBcd(time.bSecond)); // 0 to bit 7 starts the clock
Wire.write(decToBcd(time.bMinute));
Wire.write(decToBcd(time.bHour)); // If you want 12 hour am/pm you need to set
// bit 6 (also need to change readDateDs1307)
Wire.write(decToBcd(0)); // weekday not used
Wire.write(decToBcd(time.bDay));
Wire.write(decToBcd(time.bMonth));
Wire.write(decToBcd(time.iYear-2000));
Wire.endTransmission();
}
Complete main code:
// DCF77 and RTC test sketch by 'jurs' for Arduino forum
// hardware required:
// RTC module: DS1307 or DS3231
// DCF77 module
#include <Wire.h>
// begin of user configuration area
#define DEBUGMODE 1 // 1 or 0 to show or not show debug messages
#define DCFPIN 2 // data pin of DCF77 module
#define DCF_INPUTMODE INPUT // INPUT or INPUT_PULLUP
#define INVERTEDSIGNAL false // false= normal signal, true= inverted signal
// end of user configuration area
#include "jursDCFtime.h"
void setup() {
Serial.begin(9600);
Serial.println(F("\nDCF77 and RTC test sketch by 'jurs'"));
if (RTCinit()) Serial.println(F("RTC OK"));
else Serial.println(F("RTC FAIL"));
pinMode(DCFPIN, DCF_INPUTMODE);
}
unsigned long lastPrintTimeMillis;
void loop() {
sTime time;
if (dcfUpdate())
{
//(lastValidDCFtime);
Serial.println("DCF77 TIME TELEGRAM RECEIVED!");
}
if (millis()-lastPrintTimeMillis>=1000) // each second
{ // read time from RTC and print it to Serial
lastPrintTimeMillis+=1000;
char buf[21];
RTCreadTime(time);
snprintf(buf,sizeof(buf),"%02d.%02d.%04d %02d:%02d:%02d", time.bDay, time.bMonth, time.iYear, time.bHour, time.bMinute, time.bSecond);
Serial.println(buf); // print date and time
}
}
Full code of the file "jursDCFtime.h", required by the main code:
#include <Arduino.h>
// RTC functions
struct sTime // structure for holding a date and a time
{
int iYear;
byte bMonth;
byte bDay;
byte bHour;
byte bMinute;
byte bSecond;
};
sTime dateTime; // global variable to hold a full date/time struct
byte daysInMonth(int year, byte month)
{
if (month == 4 || month == 6 || month == 9 || month == 11)
return 30;
else if (month == 2)
{
bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
if (isLeapYear) return 29;
else return 28;
}
else return 31;
}
boolean validDate(int year, int month, int day)
{
boolean valid=true;
if (year<2000 || year>2199) valid=false;
if (month<1 || month>12) valid=false;
if (day<1 || day> daysInMonth(year, month)) valid=false;
return valid;
}
boolean validTime(int hour, int minute, int second)
{
boolean valid=true;
if (hour<0 || hour>=24) valid=false;
if (minute<0 || minute>=60) valid=false;
if (second<0 || second>=60) valid=false;
return valid;
}
void timeTask()
{
static unsigned long lastUpdate;
if (millis()-lastUpdate>=1000)
{
lastUpdate+=1000;
dateTime.bSecond++;
if (dateTime.bSecond>=60) {dateTime.bSecond=0; dateTime.bMinute++;}
if (dateTime.bMinute>=60) {dateTime.bMinute=0; dateTime.bHour++;}
if (dateTime.bHour>=24) {dateTime.bHour=0; dateTime.bDay++;}
if (dateTime.bDay>daysInMonth(dateTime.iYear, dateTime.bMonth)) {dateTime.bDay=1; dateTime.bMonth++;}
if (dateTime.bMonth>12) {dateTime.bMonth=1; dateTime.iYear++;}
}
}
//###################################
// RTC routines for DS1307 and DS3231
//###################################
#include <Wire.h>
#define RTC_I2C_ADDRESS 0x68 // // I2C adress of DS1307 and DS3231 RTC
byte decToBcd(byte val) // RTC helper function
// Convert decimal number to binary coded decimal
{
return ( (val/10*16) + (val%10) );
}
byte bcdToDec(byte val) // RTC helper function
// Convert binary coded decimal to decimal number
{
return ( (val/16*10) + (val%16) );
}
boolean RTCinit()
{
Wire.begin();
delay(10); // small delay to stabilize I2C bus voltage
Wire.beginTransmission(RTC_I2C_ADDRESS);
Wire.write(0);
return (Wire.endTransmission()==0);
}
void RTCreadTime(sTime &time);
void RTCreadTime(sTime &time)
// read current time from RTC
{
// Reset the register pointer
Wire.beginTransmission(RTC_I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(RTC_I2C_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
time.bSecond= bcdToDec(Wire.read() & 0x7f);
time.bMinute= bcdToDec(Wire.read());
time.bHour = bcdToDec(Wire.read() & 0x3f); // Need to change this if 12 hour am/pm
bcdToDec(Wire.read()); // day of week not used
time.bDay = bcdToDec(Wire.read());
time.bMonth = bcdToDec(Wire.read());
time.iYear = bcdToDec(Wire.read())+2000;
}
void RTCwriteTime(sTime time)
// write time to RTC
{
Wire.beginTransmission(RTC_I2C_ADDRESS);
Wire.write(0);
Wire.write(decToBcd(time.bSecond)); // 0 to bit 7 starts the clock
Wire.write(decToBcd(time.bMinute));
Wire.write(decToBcd(time.bHour)); // If you want 12 hour am/pm you need to set
// bit 6 (also need to change readDateDs1307)
Wire.write(decToBcd(0)); // weekday not used
Wire.write(decToBcd(time.bDay));
Wire.write(decToBcd(time.bMonth));
Wire.write(decToBcd(time.iYear-2000));
Wire.endTransmission();
}
// DCF77 functions
#define PULSE_ERRORLIMIT 40 // 40 ms seems to be a suitable value
#define PULSE_SHORTSECOND (1000-PULSE_ERRORLIMIT)
#define PULSE_LONGSECOND (1000+PULSE_ERRORLIMIT)
#define PULSE_MINUTEMARK (2000-PULSE_ERRORLIMIT)
// 8 Bytes = 64 Bits to store all 59 DCF bits in a minute
uint8_t dcfBits[8];
byte dcfBitcount;
boolean parityOK(byte startbit, byte paritybit)
{ // test parity bit in the range startbit ... paritybit-1
byte p=0;
for (int i=startbit; i<=paritybit;i++) p+= bitRead(dcfBits[i/8],i%8);
if (p%2 == 0) return true; // even parity detected
else return false;
}
byte dcfDecodeBCD(byte startbit, byte numbits)
{ // return BCD encoded byte-value beginning at startbit
byte b=0;
for (int i=startbit;i<startbit+numbits;i++) bitWrite(b,i-startbit, bitRead(dcfBits[i/8],i%8));
return b;
}
sTime lastValidDCFtime;
boolean dcfDecodeTime()
{
int hour, minute, day, month, year;
byte resultCode, parityError=0;
#if (DEBUGMODE==1)
// print bits of time code to serial
for (int i=0;i<dcfBitcount;i++) Serial.print(bitRead(dcfBits[i/8],i%8));
Serial.print('\t');Serial.println(dcfBitcount);
#endif
if(!parityOK(21,28)) bitSet(parityError,0); // parity error minute
if(!parityOK(29,35)) bitSet(parityError,1); // parity error hour
if(!parityOK(36,58)) bitSet(parityError,2); // parity error date
hour = 10*dcfDecodeBCD(33,2); // tens of hours, 2 bit
hour += dcfDecodeBCD(29,4); // single hours, 4 bit
minute = 10*dcfDecodeBCD(25,3); // tens of minutes, 3 bit
minute += dcfDecodeBCD(21,4); // single minutes, 4 bit
day = 10*dcfDecodeBCD(40,2); // day of month (tens), 2 bit
day += dcfDecodeBCD(36,4); // day of month (single), 4 bit
month = 10*dcfDecodeBCD(49,1); // tens of month, 1 bit
month += dcfDecodeBCD(45,4); // single digit of month, 4 bit
year = 10*dcfDecodeBCD(54,4); // tens of year, 4 bit
year += dcfDecodeBCD(50,4); // single digit of year, 4 bit
if (dcfBitcount!=59)
{
#if (DEBUGMODE==1)
Serial.println("Error: Time code must contain 59 bits!");
#endif
}
else if (parityError)
{
#if (DEBUGMODE==1)
Serial.println("Error: Wrong parity bit detected!");
#endif
}
else
{
lastValidDCFtime.bHour=hour;
lastValidDCFtime.bMinute=minute;
lastValidDCFtime.bSecond=0;
lastValidDCFtime.bDay=day;
lastValidDCFtime.bMonth=month;
lastValidDCFtime.iYear=2000+year;
#if (DEBUGMODE==1)
Serial.print(hour);Serial.print(':');
Serial.print(minute);Serial.print(":00 ");
Serial.print(day);Serial.print('/');
Serial.print(month);Serial.print('/');
Serial.println(year);
#endif
dcfBitcount=0;
return true;
}
dcfBitcount=0;
return false;
}
boolean dcfHandleBit(uint16_t hiTime, uint16_t pulseTime)
{
if (dcfBitcount<60)
{
if (hiTime<150) bitClear(dcfBits[dcfBitcount/8],dcfBitcount%8);
else bitSet(dcfBits[dcfBitcount/8],dcfBitcount%8);
dcfBitcount++;
}
if (pulseTime>=PULSE_MINUTEMARK) return dcfDecodeTime();
return false;
}
boolean dcfUpdate()
{
static boolean lastState;
static unsigned long lastChangeTime;
static uint16_t hiMillis,loMillis;
static byte cnt;
boolean state= digitalRead(DCFPIN);
if (INVERTEDSIGNAL) state=!state;
if (state!=lastState)
{
long timeDiff=millis()-lastChangeTime;
lastState=state;
lastChangeTime+= timeDiff;
if (state)
{
cnt++;
loMillis+= timeDiff;
uint16_t pulsetime=hiMillis+loMillis;
if ((pulsetime>=PULSE_SHORTSECOND && pulsetime<=PULSE_LONGSECOND)|| pulsetime>=PULSE_MINUTEMARK)
{
#if (DEBUGMODE==1)
Serial.print(cnt);Serial.print('\t');
Serial.print(hiMillis);Serial.print('\t');
Serial.print(loMillis);Serial.print('\t');
Serial.print(pulsetime);Serial.print('\t');
Serial.println();
#endif
boolean result=dcfHandleBit(hiMillis, pulsetime);
hiMillis=0;
loMillis=0;
cnt=0;
return result;
}
}
else hiMillis+= timeDiff;
}
return false;
}
I was thinking of using the RTCLib library since it has a function that could calculate the day of the week and try to somehow control the slideshow with the lastPrintTimeMillis parameter. However, this solution seems cumbersome to me and I was therefore thinking of correcting the "jursDCFtime.h" file, but I didn't know how to do it.
Can you help me? Thank you in advance for your attention.
1 post - 1 participant