#include <Wire.h> //Standard Arduino Wire library #include <LowPower.h> //Rocket Scream low power library for Arduino available at https://github.com/rocketscream/Low-Power //CONFIG SECTION const byte RTC_ADDRESS = 0x68; //Constant for I2C address of RTC board - usually but not necessarily 0x68 byte mSecs; //Global Variable used to read seconds from DS3231 time registers (0-59) byte mMins; //Global Variable used to read minutes from DS3231 time registers (0-59) byte mHours; //Global Variable used to read hours from DS3231 time registers (0-23) byte mdoW; //Global Variable used to read Day of Week Index from DS3231 time registers (1-7) byte mdoM; // Global Variable used to read Day of Month index (1-31)from DS3231 time registers byte mMonth; //Global Variable used to read Month index (1-12) from DS3231 time registers byte mYear; //Global Variable used to read year (1-99) from DS3231 time registers volatile byte rtcStatus = 0; //Global Variable used to read the state of DS3231 registers volatile byte rtcControl = 0 ;//Global Variable used to set the state of DS3231 registers volatile int rtcInterruptflag = 0; //Global Variable used to flag an external interrupt event byte timer1_Secs = 10; //Alarm1 timer Seconds required (0-59) byte timer1_Mins = 0; //Alarm1 timer Minutes required (0-509) byte timer1_Hours = 0; //Alarm1 timer Hours required (0-23) byte timer2_Mins = 1; //Alarm2 timer Minutes required (0-59)- Timer 2 only has minutes resolution so the first one will occur at an unpredictable time between 1 second and 59 seconds after setting timer then will be accurate byte timer2_Hours = 0; //Alarm2 timer Hours required (0-23) int almIntPin = 2; //External interrupt pin for your board - usually #2 for arduino //END CONFIG SECTION void setup() { Serial.begin(9600); Wire.begin(); pinMode(almIntPin, INPUT); attachInterrupt(digitalPinToInterrupt(almIntPin), alarmInterrupt, FALLING); initialiseRTC(); setTimer1(timer1_Hours, timer1_Mins, timer1_Secs); setTimer2(timer2_Hours, timer2_Mins); } void loop() { //readTimeAndDate(mSecs,mMins,mHours,mdoW,mdoM,mMonth,mYear); gotoSleep(); //LOOP RESUMES HERE AFTER POWER UP if (rtcInterruptflag = -1) { // If the interrupt was generated by interrupt pin connected to RTC then one of the alarm flags will be set if (checkAlarmFlag1() == true) { Serial.println("Alarm 1 woke me up"); setTimer1(timer1_Hours, timer1_Mins, timer1_Secs); //Reset timer } if (checkAlarmFlag2() == true) { Serial.println("Alarm 2 woke me up"); setTimer2(timer2_Hours, timer2_Mins); //Reset timer } } } void gotoSleep() { //Sends the arduino to power down state Serial.println("Going to sleep....."); delay(100); LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); //WAKES UP HERE } void alarmInterrupt() { //The interrupt routine called when an external signal is applied to external interrupt0 (pin2) rtcInterruptflag = -1; //sets the interrupt flag so that the main loop can detect the interrupt event has occurred } void setAlarm1Registers(byte a_hour, byte a_min, byte a_sec) { //Sets the alarm time to alarm1 registers and resets the alarm1 flag //Write to alarm seconds register rtcControl = decToBcd(a_sec); //Converts number value of seconds delay to binary coded decimal format needed by DS3231 register bitWrite(rtcControl, 7, 0); // Sets bit 7 of the register byte to 0 to enable the seconds alarm Wire.beginTransmission(RTC_ADDRESS); //Initialise I2C communication with DS3231RTC Wire.write(0x07); //Set DS3231 register to be read/written by I2C Wire.write(rtcControl); //writes the modified byte to the DS3231 register Wire.endTransmission(); //completes I2C transaction rtcControl = decToBcd(a_min); //Write to alarm minutes register bitWrite(rtcControl, 7, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x08); Wire.write(rtcControl); Wire.endTransmission(); rtcControl = decToBcd(a_hour); //Write to alarm hours register bitWrite(rtcControl, 7, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x09); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Reset alarm1 flag Wire.write(0x0F); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0F); Wire.write(rtcControl); Wire.endTransmission(); } void setAlarm2Registers(byte a_hour, byte a_min) { //Sets the alarm time to alarm2 registers and resets the alarm2 flag rtcControl = decToBcd(a_min); //Write to alarm minutes register bitWrite(rtcControl, 7, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0B); Wire.write(rtcControl); Wire.endTransmission(); rtcControl = decToBcd(a_hour); //Write to alarm hours register bitWrite(rtcControl, 7, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0C); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Reset alarm2 flag Wire.write(0x0F); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 1, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0F); Wire.write(rtcControl); Wire.endTransmission(); } void ReadTime() { Wire.beginTransmission(RTC_ADDRESS); //Read Time Registers Wire.write(0x00); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 3); rtcControl = Wire.read(); mSecs = bcd2Dec(rtcControl); rtcControl = Wire.read(); mMins = bcd2Dec(rtcControl); rtcControl = Wire.read(); mHours = bcd2Dec(rtcControl); } void setTimer1(byte numHours, byte numMinutes, byte numSeconds) { //Call this with delay Hours Mins Seconds required - The alarm time is calculated from current time plus alarm delay ReadTime(); byte a_hour = (mHours + numHours); //Reads the current time and adds the delay required byte a_min = (mMins) + numMinutes; byte a_sec = (mSecs) + numSeconds; if (a_sec > 59) { a_sec = a_sec - 60; a_min++; } if (a_min > 59) { // If there are more than 59 minutes add 1 to hours delay and subtract 60 from minutes a_min = a_min - 60; a_hour++; } if (a_hour > 23) { // If there are more than 23 hours subtract 24 from hours a_hour = a_hour - 24; } setAlarm1Registers(a_hour, a_min, a_sec); //write the alarm match time to the alarm time registers enableAlarmInterrupt1(); // Enable interrupts for the alarm by setting AL1E high } void setTimer2(byte numHours, byte numMinutes) { //Call this with delay Hours Mins Seconds required - The alarm time is calculated from current time plus alarm delay ReadTime(); byte a_hour = (mHours + numHours); byte a_min = (mMins) + numMinutes; if (a_min > 59) { a_min = a_min - 60; a_hour++; } if (a_hour > 23) { a_hour = a_hour - 24; } setAlarm2Registers(a_hour, a_min); enableAlarmInterrupt2(); } void initialiseRTC() { Serial.println("initialising RTC"); Wire.beginTransmission(RTC_ADDRESS); //Initialise I2C communication with DS3231RTC Wire.write(0x0E); //Set DS3231 register to be read/written by I2C Wire.endTransmission(); //completes I2C transaction Wire.requestFrom(RTC_ADDRESS, 1); //load the relevant register(s) into the I2C interface register rtcControl = Wire.read(); //read the register from the I2C interface bitWrite(rtcControl, 7, 0); //sets EOSC bit in Control Register to enable running on battery bitWrite(rtcControl, 6, 0); //sets BBSQ bit in Control Register to disable square wave output running on battery bitWrite(rtcControl, 2, 1); //sets INTCN bit in Control Register to enable interrupt signal bitWrite(rtcControl, 1, 0); //sets ALM2E bit in Control Register to disable alarm2 Note setting timer1 automatically enables ALM2E bit bitWrite(rtcControl, 0, 0); //Sets ALM1E bit in Control Register to disable alarm1Note setting timer1 automatically enables ALM1E bit Wire.beginTransmission(RTC_ADDRESS); //Initialise I2C communication with DS3231RTC Wire.write(0x0E); //Set DS3231 register to be read/written by I2C Wire.write(rtcControl); //writes the modified control byte back to the DS3231 register Wire.endTransmission(); //completes I2C transaction Wire.beginTransmission(RTC_ADDRESS); //zero alarm1 seconds register Wire.write(0x07); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 0); bitWrite(rtcControl, 6, 0); bitWrite(rtcControl, 5, 0); bitWrite(rtcControl, 4, 0); bitWrite(rtcControl, 3, 0); bitWrite(rtcControl, 2, 0); bitWrite(rtcControl, 1, 0); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x07); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Zero alarm1 minutes register Wire.write(0x08); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 0); bitWrite(rtcControl, 6, 0); bitWrite(rtcControl, 5, 0); bitWrite(rtcControl, 4, 0); bitWrite(rtcControl, 3, 0); bitWrite(rtcControl, 2, 0); bitWrite(rtcControl, 1, 0); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x08); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Zero alarm1 hours register Wire.write(0x09); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 0); bitWrite(rtcControl, 6, 0); bitWrite(rtcControl, 5, 0); bitWrite(rtcControl, 4, 0); bitWrite(rtcControl, 3, 0); bitWrite(rtcControl, 2, 0); bitWrite(rtcControl, 1, 0); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x09); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Zero alarm1 days register Wire.write(0x0A); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 1); //NB Bit7 of the Alarm1 seconds, minutes,hours,days and date registers define what the alarm match is we will not be using days at the moment so days bit7 must be set to 1 to disable it but it is there for future expansion. bitWrite(rtcControl, 6, 0); bitWrite(rtcControl, 5, 0); bitWrite(rtcControl, 4, 0); bitWrite(rtcControl, 3, 0); bitWrite(rtcControl, 2, 0); bitWrite(rtcControl, 1, 0); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0A); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Zero alarm2 minutes register Wire.write(0x0B); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 0); bitWrite(rtcControl, 6, 0); bitWrite(rtcControl, 5, 0); bitWrite(rtcControl, 4, 0); bitWrite(rtcControl, 3, 0); bitWrite(rtcControl, 2, 0); bitWrite(rtcControl, 1, 0); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0B); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Zero alarm2 hours register Wire.write(0x0C); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 0); bitWrite(rtcControl, 6, 0); bitWrite(rtcControl, 5, 0); bitWrite(rtcControl, 4, 0); bitWrite(rtcControl, 3, 0); bitWrite(rtcControl, 2, 0); bitWrite(rtcControl, 1, 0); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0C); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Zero alarm2 days register Wire.write(0x0D); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 1);//NB Bit7 of the Alarm1 seconds, minutes,hours,days and date registers define what the alarm match is we will not be using days at the moment so days bit7 must be set to 1 to disable it but it is there for future expansion. bitWrite(rtcControl, 6, 0); bitWrite(rtcControl, 5, 0); bitWrite(rtcControl, 4, 0); bitWrite(rtcControl, 3, 0); bitWrite(rtcControl, 2, 0); bitWrite(rtcControl, 1, 0); bitWrite(rtcControl, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0D); Wire.write(rtcControl); Wire.endTransmission(); Wire.beginTransmission(RTC_ADDRESS); //Initialises Alarm Flags as disabled and other control flags to a known but not relevant state Wire.write(0x0F); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); bitWrite(rtcControl, 7, 0); // resets OSF flag to 0 bitWrite(rtcControl, 3, 0); // resets 32HZ flag to 0 bitWrite(rtcControl, 1, 0); // resets Alarm2 flag to 0 bitWrite(rtcControl, 0, 0); // resets Alarm1 flag to 0 Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0F); Wire.write(rtcControl); Wire.endTransmission(); } byte decToBcd(byte val) { //Decimal to binary coded decimal converter converts simple numbers into the binary coded decimal form that the DS3231 registers use. return ((val / 10 * 16) + (val % 10)); } byte bcd2Dec(byte val) { //Binary coded decimal to decimal converter converts binary coded DS3231 register values to simple numbers return ((val / 16 * 10) + (val % 16)); } bool checkAlarmFlag1() { //The alarm flag is set to 1 if the alarm has "gone off". this routine checks if it is set to 1, resets it to 0 if it ir and returns true or false bool alFlag1 = false; Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0F); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcStatus = Wire.read(); if (bitRead(rtcStatus, 0) == 1) { //if alarm1 flag is set then clear it alFlag1 = true; bitWrite(rtcStatus, 0, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0F); Wire.write(rtcStatus); Wire.endTransmission(); } if (testAlarmInterrupt1isEnabled()==true){ return alFlag1; } else { return false; } } bool checkAlarmFlag2() { //The alarm flag is set to 1 if the alarm has "gone off". this routine checks if it is set to 1, resets it to 0 if it ir and returns true or false bool alFlag2 = false; Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0F); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcStatus = Wire.read(); if (bitRead(rtcStatus, 1) == 1) { //if alarm1 flag s set alFlag2 = true; bitWrite(rtcStatus, 1, 0); Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0F); Wire.write(rtcStatus); Wire.endTransmission(); } if (testAlarmInterrupt2isEnabled()==true){ return alFlag2; } else { return false; } } void enableAlarmInterrupt1() { //enable the creation of an interrupt on an alarm flag being set, the alarm flag will be set and trigger the interrupt Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); if (bitRead(rtcControl, 0) == 0) { bitWrite(rtcControl, 0, 1); //sets AlIE bit in Control Register to enable interrupt signal Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.write(rtcControl); Wire.endTransmission(); } } void disableAlarmInterrupt1() { //disable the creation of an interrupt on an alarm flag being set, the alarm flag will still be set but the interupt can be suppressed Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); if (bitRead(rtcControl, 0) == 1) { bitWrite(rtcControl, 0, 0); //Zeros AlIE bit in Control Register to disable interrupt signal Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.write(rtcControl); Wire.endTransmission(); } } void enableAlarmInterrupt2() { //enable the creation of an interrupt on an alarm flag being set, the alarm flag will be set and trigger the interrupt. Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); if (bitRead(rtcControl, 1) == 0) { bitWrite(rtcControl, 1, 1); //sets A2IE bit in Control Register to enable interrupt signal Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.write(rtcControl); Wire.endTransmission(); } } void disableAlarmInterrupt2() { //disable the creation of an interrupt on an alarm flag being set, the alarm flag will still be set but the interupt can be suppressed Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); if (bitRead(rtcControl, 1) == 1) { bitWrite(rtcControl, 1, 0); //Zeros A2IE bit in Control Register to disable interrupt signal Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.write(rtcControl); Wire.endTransmission(); } } bool testAlarmInterrupt1isEnabled() { //Check whether the alarm interrupt AL1E is enabled Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); if (bitRead(rtcControl, 0) == 0) { return false; } else { return true; } } bool testAlarmInterrupt2isEnabled() { //Check whether the alarm interrupt AL2E is enabled Wire.beginTransmission(RTC_ADDRESS); Wire.write(0x0E); Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 1); rtcControl = Wire.read(); if (bitRead(rtcControl, 1) == 0) { return false; } else { return true; } } void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { //Sets the time and date on the DS3231 // sets time and date data to DS3231 Wire.beginTransmission(RTC_ADDRESS); Wire.write(0); // set next input to start at the seconds register Wire.write(decToBcd(second)); // set seconds Wire.write(decToBcd(minute)); // set minutes Wire.write(decToBcd(hour)); // set hours Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday) Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31) Wire.write(decToBcd(month)); // set month Wire.write(decToBcd(year)); // set year (0 to 99) Wire.endTransmission(); } void readTimeAndDate(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { //Reads the time and date on the DS3231 // reads time and date data from DS3231 Wire.beginTransmission(RTC_ADDRESS); Wire.write(0); // set next input to start at the seconds register Wire.endTransmission(); Wire.requestFrom(RTC_ADDRESS, 7); rtcStatus = Wire.read(); second = bcd2Dec(rtcStatus); rtcStatus = Wire.read(); minute = bcd2Dec(rtcStatus); rtcStatus = Wire.read(); hour = bcd2Dec(rtcStatus); rtcStatus = Wire.read(); dayOfWeek = bcd2Dec(rtcStatus); rtcStatus = Wire.read(); dayOfMonth = bcd2Dec(rtcStatus); rtcStatus = Wire.read(); month = bcd2Dec(rtcStatus); rtcStatus = Wire.read(); year = bcd2Dec(rtcStatus); Serial.println(second ); Serial.println( minute); Serial.println(hour ); Serial.println(dayOfWeek ); Serial.println(dayOfMonth ); Serial.println(month ); Serial.println( year); }
Arduino Mission
Sunday, 24 March 2019
HOW TO USE DS3231 RTC AS A TIMER TO WAKE ARDUINO FROM SLEEP
About using dS3231 as a timer
Subscribe to:
Posts (Atom)
HOW TO USE DS3231 RTC AS A TIMER TO WAKE ARDUINO FROM SLEEP
About using dS3231 as a timer #include <Wire.h> //Standard Arduino Wire library #include <LowPower.h> //Rocket Scream low pow...
How to use the DS3231 Real Time Clock as a timer to wake Arduino from sleep
-
About using dS3231 as a timer #include <Wire.h> //Standard Arduino Wire library #include <LowPower.h> //Rocket Scream low pow...