Quantcast
Channel: Arduino Forum - Latest topics
Viewing all articles
Browse latest Browse all 15374

Setting Day of the week using DCF77 with RTC3231

$
0
0

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

Read full topic


Viewing all articles
Browse latest Browse all 15374

Trending Articles