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