Can read, but fail to set time on DS3231 RTC

I'm trying to use a DS3231 on my sprinkler controller, for the simple reason that power failures here are so common that it's too much trouble to reset. That, and it will consequentially toss me outside of permitted days and hours.

At some point, I successfully set it, as it is configured.

I've stripped most of the project out of the following, and am doing everything in setup(). I also left in the bluetooth communications, as I'll want to test with that, too.

I'm directly reading and writing to the unit, using the Wire library.

What is left of the code successfully reads the RTC with dhGetRtcTime(), and kicks out the bytes. (values in bcd; seconds, minutes, hour, date, month, year).

I then try to set time with dhSetRtcTime. The Write() returns status 0, success.

But when I then read another couple of times, it still has the original time plus a few intervening seconds (which seem to be the correct number).

I also seem to lose the #useAltSoftSerialBt of line 11 by line 171. However, the definition seems to get used at line 94, defining addresses and haveRtc.

the output is

rtc is: unknown
in dhGetRtcTime
Getting rtc time:
0:21
1:3
2:0
3:1
4:2
5:3
6:4
leaving setup!
setting rtc time
rtc time supposedly set, status 0
in dhGetRtcTime
Getting rtc time:
0:23
1:3
2:0
3:1
4:2
5:3
6:4
in dhGetRtcTime
Getting rtc time:
0:28
1:3
2:0
3:1
4:2
5:3
6:4

The code is




// #include <Time.h>
#include <TimeLib.h>

//the rtc to use

#define useRtcDS3231

#define useAltSoftSerialBt

//define this if we want to talk to the at=09 from the serial monitor
#define relaySerialToBtserial

// now that general defines are made as to our hardware, bring in the dhMegaLib

#include "dhMegaLib.h"

#include <Time.h>
long unsigned int seconds = 0;


//figure out where bt goes

#ifdef useAltSoftSerialBt
AltSoftSerial btSerial;

#endif 


//and for debug
#ifdef useAltSoftSerialDbg
#ifndef AltSoftSerial_h
#include "altSoftSerial.h"
#endif
altSoftSerial dbgSerial;


#else
nullSerial dbgSerial;
#endif


//sort out the consequences the definitions


#ifdef useSoftwareSerialBt

//omitted

#elif defined(useAltSoftSerialBt)

//we want an altsoftserial for bt. On nano, rx=D8 and TX=D9

#define usingAltSoftSer
const srlTyps btTyp = ALTSOFTSERIAL;
const srlTyps  dbgTyp = PIGGYBACK;


#endif


#ifdef usingAltSoftSer
#include <AltSoftSerial.h>
#endif

//for the AT-09.  THis shoud probably go in a #ifdef, but . . .
//the pin to power the AT-09
const byte btSerialPowerPin = 11;
//and to read its status
const byte btSerialStatusPin = 10;
#define BT_POWER_OFF LOW
#define BT_POWER_ON 1-BT_POWER_OFF

//start with the bluetooth off
byte btSerialStatus = BTOFF;


// now a device to send monitor messages
#if dbgTyp==HARDWARE
HardwareSerial &monSerial = Serial;
#elif dbgTyp==ALTSOFTSERIAL
AltSoftSerial monSerial;
#elif dbgTyp==PIGGYBACK
AltSoftSerial &monSerial = btSerial;
#else dbgTyp==NONE
//we *could* just not have  monSerial, but this will get optimized out, so that we can keep debug code
nullSerial monSerial;
#endif  //monitor hardware #if



#ifdef useRtcDS3231
#define haveRTC
#define rtcAdr 0x68
#include <Wire.h>
//#include <DS3231.h>
#endif





//places to keep incoming and outgoing bluetooth data

// the maximum bluetooth buffer size
const byte btInBfrSiz = 17; //for 16 characters and a terminator
char btInBfr[btInBfrSiz] = {'\0'};
byte  btInBfrPtr = 0; //the pointer to wher we are loading in the buffer
unsigned long btLastCharMs = 0; //when we received the last char
const byte btCharTimeout = 100; //this is probably too much, and can drop to a few ms





void setup() {


  //wait for circuits to stabilize from power loss
  delay(3000);
  //get the monitor going
  monSerial.begin(9600);




  //set up the bluetooth serial.  this should work for all three
  //  monSerial.println("setting up bluetooth");
  //  delay(100);
  pinMode (btSerialPowerPin, OUTPUT);
  //  //the pin to monitor the status
  pinMode(btSerialStatusPin, INPUT);
  //make sure it's off
  btSerialTurnOff();

  //if aproprate, set up the serial for the monitor

  //do some other things while bluetooth stabilizes

  // . . . [omitted]


  //return to bluetooth setup
  // let the bt turn back on
  //  monSerial.println("Calling btSerialTurnOn.");
  btSerialTurnOn();
  //monSerial.println("back from btSerialTurnOn.");

  //flush the bluetooth input
  delay(100);

  while (btSerial.available()) {
    //    monSerial.print("Got: "); monSerial.println(btSerial.peek());
    btSerial.read();
  }
  //monSerial.print(btInBfrPtr);monSerial.print("_");monSerial.println(strlen(btInBfr));




  // get the time  (or wait for it to be set)


  //if there is an rtc connected, get the time from it
#ifdef haveRTC
  //this should be from a general i2c test, not here:
  monSerial.print("rtc is: ");

#ifdef  defined(useRtcDS3231)

  monSerial.println("DS3231");

#else
  monSerial.println("unknown");
#endif  //useRtcPfc8583

  byte theData[7];

  dhGetRtcTime(theData);
 
#endif

  monSerial.println("***leaving setup***!");

  //now try setting it

  byte newDate[] = { 00, 01, 02, 03, 04,05, 06 };
  dhSetRtcTime(newDate,7);

 
  delay(2000);
   dhGetRtcTime(theData);

 delay(5000);
   dhGetRtcTime(theData);

}

void loop() {

  //monSerial.print("begining loop, timeProg="); monSerial.println(timeProg);

  //delay(500);
  //check for bt data and process it
//  btSerialScan();

}


//functions to power bt up & down


void btSerialTurnOn() {
  //monSerial.println("attempting to activate serial");
  digitalWrite(btSerialPowerPin, BT_POWER_ON); //turn it on
  delay(100);
  //monSerial.println();
  //monSerial.print("digital: ") & monSerial.print(digitalRead(btSerialStatusPin));  monSerial.print("; Analog: "); monSerial.println(analogRead(btSerialStatusPin));
  btSerial.begin(9600);
  btSerialStatus = BTAT; //it is ready for commands

}

void btSerialTurnOff() {
  digitalWrite(btSerialPowerPin, BT_POWER_OFF); //turn it off
  pinMode(8, INPUT);
  pinMode(9, INPUT);
  btSerialStatus = BTOFF;

}


void btSerialKill() {
  //kill the connection by turning it off and then back on
  btSerialTurnOff();
  //turn off the tx pin due to parasitic power draw
  //digitalWrite(btSerialPowerPin, BT_POWER_OFF);
  delay(1); //1 ms seems to be enough for the kill.  It survives some microseconds on the capacitor
  //and now bring it back up

  btSerialTurnOn();

}


//capture bluetooth data as it comes
void btSerialScan() {
  //see if data is available and process
  //monSerial.print("in btSS: ");monSerial.println(btInBfrPtr);
  if (btSerial.available()) {
    monSerial.print("bt available: "); monSerial.print(btSerial.available());
    monSerial.print("_: "); monSerial.println(btInBfrPtr);
  }    //
  //  if (btInBfrPtr && (millis() - btCharTimeout > btLastCharMs)) {
  //    monSerial.print("timeout reached: "); monSerial.print(millis()); monSerial.print("_: "); monSerial.println(btInBfrPtr);Serial.flush();
  //  }



  //check for switching on
  if ( (btSerialStatus == BTAT) && (digitalRead(btSerialStatusPin) == HIGH)) {
    //it has connected
    monSerial.println("we are connected!");
    btSerialStatus = BTON;
  } else if ( (btSerialStatus == BTON) && (digitalRead(btSerialStatusPin) == LOW)) {
    monSerial.println("we have been disconnected!!!");
    btSerialStatus = BTAT;
  }



  //check for timeout
  if ((btInBfrPtr > 0) && (millis() - btCharTimeout > btLastCharMs) ) {
    //then it's gone too longe since the last character.  pad the string with null
    //monSerial.print("padding "); monSerial.print(  btInBfrPtr);
    //    monSerial.print(" - "); monSerial.print(millis());
    //    monSerial.print("_"); monSerial.println(btLastCharMs, DEC);
    //monSerial.println(btInBfr);
    //    Serial.flush();
    for (btInBfrPtr; btInBfrPtr < btInBfrSiz - 1; btInBfrPtr++) {
      btInBfr[btInBfrPtr] = '\0';
      //monSerial.print("  bfrPtr: ");monSerial.println(btInBfrPtr);
    }
    //monSerial.println(btInBfrPtr,HEX);
  } else {



    while ((btSerial.available() ) &&  (btInBfrPtr < (btInBfrSiz - 1)) ) {
      //this means serial data available from bt.Serial and still space in buffer


      //      monSerial.print("Data coming: "); monSerial.print( btInBfrPtr); monSerial.print("_: ");monSerial.print((char) btSerial.peek());
      //          monSerial.print(" ");monSerial.println(btSerial.peek());

      // add it to the input buffer
      btInBfr[btInBfrPtr] = btSerial.read();
      btInBfrPtr++;

      //log when this happened
      btLastCharMs = millis();
    };        //end while available

  }       //end else

  //if we have reached maximum size in bt buffer, process the command

  if ( btInBfrPtr >= (btInBfrSiz - 1)  ) {

    //    monSerial.print("full string!  "); monSerial.print(btInBfrPtr); monSerial.print("  : ");
    //    monSerial.println(btInBfr);
    doBtInBfr();

    //reset so that it can go again
    btInBfrPtr = 0;
    //we could re-zero the array, but why?


  }

  // relay the monSerial to the bluetooth
  //this would mean that data is available from the serial monitor
  // monSerial.write("_"); monSerial.write(monSerial.peek());
  //monSerial.println("Sending: ");
  if (monSerial.available()) btSerial.write(monSerial.read());


} //end btSerialScan


void   doBtInBfr() {
  //here we interpret the input string
  monSerial.print("parsing : "); monSerial.println(btInBfr);
  //this needs to behave differently in command mode and once enabled

  switch (btSerialStatus) {
    case BTAT:
      //it's still in command mode

      monSerial.print("got: "); monSerial.println(btInBfr);


    // break;
    case BTON:
      //so we are live and looking for commands
      switch (btInBfr[0]) {

        case 's':
          //talk back
          monSerial.write("you said : ");
          monSerial.println(&btInBfr[1]);
          btSerial.write("you said : ");
          btSerial.println(&btInBfr[1]);
          break;


#ifdef haveRTC

#endif


        case 'k':
          // kill the connection
          btSerialKill();
          break;


      }               //the btInBfr[0] switch

  } // the btSerialSttus switch

  //reset the buffer
  btInBfrPtr = 0;
} //en



#ifdef haveRTC

void dhSetRtcTime( byte * theData, byte theLength) {
  //data should come as bcd anyway, probably from the phone
  //240429: assume an excess character ('c') at beginning from bluetooth)
  monSerial.println("setting rtc time");
  Wire.beginTransmission(rtcAdr);
  Wire.write(0x02);
  Wire.write(theData, theLength);
  byte rtcRslt = Wire.endTransmission();
  monSerial.print("rtc time supposedly set, status "); monSerial.println(rtcRslt);
}

void dhGetRtcTime(byte * theData) {

  monSerial.println("in dhGetRtcTime");
  //tell it where to start
  //monSerial.print("rtcAdr is: "); monSerial.println(rtcAdr);

  Wire.beginTransmission(rtcAdr);
#ifdef useRtcPcf8563
  Wire.write(0x02);
#elif defined(useRtcDS3231)
  //monSerial.println("writing 0x00");

  Wire.write(0x00);
  //monSerial.println("0x00 written");

#endif

  //monSerial.println("sending end Transmission");

  Wire.endTransmission();
  //monSerial.println("endTransmission written");
  //Ask for the seven bytes
  Wire.requestFrom(rtcAdr, 7);
  //monSerial.println("requested");

  byte rcdBytes = 0;
  monSerial.println("Getting rtc time: ");
  while (Wire.available()) {
    monSerial.print("  ");  monSerial.print(rcdBytes); //monSerial.print(", ");
    theData[rcdBytes++] = Wire.read();
    //monSerial.print(rcdBytes); 
    monSerial.print(":"); monSerial.println(byteOfBcd(theData[rcdBytes - 1]));
  }
#ifdef useRtcPcf8563
  Wire.write(0x02);
#endif

  //monSerial.println("leaving dhGetRtcTime");
}

#endif

//to convert back and forth between bytes and bcd

  byte bcdOfByte(byte inByte) {
    return 16 * (inByte / 10) + (inByte % 10);
  }

  byte byteOfBcd(byte inByte) {
    return 10 * (inByte >> 4 ) + (inByte & 15);
  }


//#ifdef haveRTC
//void setTimeFromRtc() {
//  //set the unix time from the rtc
//
//  //rather than converting to seconds, just convert the array
//
//  byte rtcTime[7];
//
//  //read from rtc
//  //dhGetPcf8563(rtcTime);
//  dhGetRtcTime(rtcTime);
//
//  //change it from bcd to bytes
//  //monSerial.println("in setTimeFromRtc()");
//  for (byte i = 0; i < 7; i++) {
//    //monSerial.print(i); monSerial.print(": "); monSerial.print(rtcTime[i], HEX); monSerial.print(" to ");
//    rtcTime[i] = byteOfBcd(rtcTime[i]);
//    //monSerial.println(rtcTime[i], HEX);
//  }
//
//  //note different order, and that we skip 4 for day of week
//
//  //setTime(rtcTime[0], rtcTime[1], rtcTime[2], rtcTime[3], rtcTime[5], rtcTime[6]);
//  setTime((int) rtcTime[2], (int) rtcTime[1], (int) rtcTime[0], (int) rtcTime[3], (int) rtcTime[5], (int) rtcTime[6]);
//
//
//}
//#endif

Not enough detail on your setup.
Show a diagram ( not fritzing) on your current setup.
Do you have a memory battery fitted to the DS3231and if so, have you removed the charging circuit if the battery is not rechargable.
Is the circuit running off the PC usb line currently or is it stand alone circuit running off an external supply or battery?

I strongly recommend to try unmodified clock-setting examples from one or more of the popular DS3231 libraries for Arduino.

1 Like

Can you post an annotated schematic showing all components, resistors, capacitors as this sounds like a flaky hardware connection or bias.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.