// This code is written by Paul MacDougal for the December 11, 2017 meeting of TriEmbed.org // It is released to the public domain // It does what it does. // DS3231 breakout board is: // Vcc (3.3v) // SDA (A4) // SCL (A5) // NC // GND // pin 3 of SOIC16 package (int/sqw) is hooked to INTR_PIN // Buzzer is connected as: // BUZZER_PIN -> buzzer -> GND #include #include #include #include "RTClib.h" uint8_t read_i2c_register(uint8_t addr, uint8_t reg); void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val); RTC_DS3231 rtc; #define INTR_PIN 2 #define BUZZER_PIN 5 volatile byte count = 0; void handleISR() { // ISR count++; } void printTime() { DateTime now = rtc.now(); if (now.month() < 10) { Serial.print("0"); } Serial.print(now.month()); Serial.print('/'); if (now.day() < 10) { Serial.print("0"); } Serial.print(now.day()); Serial.print('/'); Serial.print(now.year()); Serial.print(" "); if (now.hour() < 10) { Serial.print("0"); } Serial.print(now.hour(), DEC); Serial.print(':'); if (now.minute() < 10) { Serial.print("0"); } Serial.print(now.minute(), DEC); Serial.print(':'); if (now.second() < 10) { Serial.print("0"); } Serial.print(now.second(), DEC); Serial.println(); } void setup() { pinMode(INTR_PIN, INPUT_PULLUP); pinMode(BUZZER_PIN, OUTPUT); Serial.begin(19200); // Serial port to PC while (!Serial); // for Leonardo Serial.println(F("Initialized ds3231 example5 v1.0")); // initialize the RTC if (!rtc.begin()) { Serial.println("Couldn't find RTC"); while (1); } // Set A1M4 so that we get an alarm1 when hours, minutes, and seconds match write_i2c_register(DS3231_ADDRESS, 0x07, ~(0x80) & read_i2c_register(DS3231_ADDRESS, 0x07)); // A1M1 write_i2c_register(DS3231_ADDRESS, 0x08, ~(0x80) & read_i2c_register(DS3231_ADDRESS, 0x08)); // A1M2 write_i2c_register(DS3231_ADDRESS, 0x09, ~(0x80) & read_i2c_register(DS3231_ADDRESS, 0x09)); // A1M3 write_i2c_register(DS3231_ADDRESS, 0x0A, 0x80 | read_i2c_register(DS3231_ADDRESS, 0x0A)); // A1M4 // set INTCN and A1IE uint8_t val = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL); val |= 0x05; // set INTCN and A1IE val &= ~0x02; // clear A2IE write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, val); // clear both alarm flags, EN32kHz, and OSF val = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG); // OSF 0 0 0 EN32kHz BSY A2F A1F val &= ~0x03; val &= ~0x08; // EN32kHz val &= ~0x80; // OSF write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, val); printTime(); // calculate when the next alarm should happen DateTime then; TimeSpan delta(0, 0, 0, 42); // 0 days, 0 hours, 0 minutes, 42 seconds then = rtc.now() + delta; setAlarm1(then); // Attach the ISR attachInterrupt(INT0, handleISR, FALLING); delay(500); // allow serial data to go out } void loop() { uint8_t val; #if 0 val = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL); // EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE Serial.print("Control is "); Serial.print((val&0x80)?"EOSC":" "); Serial.print((val&0x40)?"|BBSQW":"| "); Serial.print((val&0x20)?"|CONV":"| "); Serial.print((val&0x10)?"|RS2":"| "); Serial.print((val&0x08)?"|RS1":"| "); Serial.print((val&0x04)?"|INTCN":"| "); Serial.print((val&0x02)?"|A2IE":"| "); Serial.println((val&0x01)?"|A1IE":"| "); #endif // read status register val = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG); // OSF 0 0 0 EN32kHz BSY A2F A1F #if 0 Serial.print("StatusReg is "); Serial.print((val&0x80)?"OSF":" "); Serial.print("| | | "); Serial.print((val&0x08)?"|32k":"| "); Serial.print((val&0x04)?"|BSY":"| "); Serial.print((val&0x02)?"|A2F":"| "); Serial.println((val&0x01)?"|A1F":"| "); #endif // clear both alarm flags write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, ~0x03 & val); if (val&1) // alarm1 has fired { printTime(); // calculate when the next alarm should happen DateTime then; TimeSpan delta(0, 0, 0, 42); // 0 days, 0 hours, 0 minutes, 42 seconds then = rtc.now() + delta; setAlarm1(then); } delay(400); // wait for serial data to go out digitalWrite(BUZZER_PIN, LOW); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // SLEEP_MODE_PWR_DOWN is lowest power state sleep_mode(); // go to sleep // wake up here on interrupt // sound the buzzer while awake digitalWrite(BUZZER_PIN, HIGH); } void setAlarm1(DateTime t) { uint8_t ss = t.second(); uint8_t mm = t.minute(); uint8_t hh = t.hour(); #if 0 Serial.print("Set alarm1 for "); if (hh < 10) { Serial.print("0"); } Serial.print(hh, DEC); Serial.print(':'); if (mm < 10) { Serial.print("0"); } Serial.print(mm, DEC); Serial.print(':'); if (ss < 10) { Serial.print("0"); } Serial.print(ss, DEC); Serial.println(); #endif uint8_t val = read_i2c_register(DS3231_ADDRESS, 0x07); val = (val&0x80) | ((ss/10)<<4) | (ss%10); write_i2c_register(DS3231_ADDRESS, 0x07, val); val = read_i2c_register(DS3231_ADDRESS, 0x08); val = (val&0x80) | ((mm/10)<<4) | (mm%10); write_i2c_register(DS3231_ADDRESS, 0x08, val); val = read_i2c_register(DS3231_ADDRESS, 0x09); val = (val&0x80) | ((hh/10)<<4) | (hh%10); write_i2c_register(DS3231_ADDRESS, 0x09, val); }