ESP8266: DS3231 alarms once per second

The objective of this post is to explain how to configure the DS3231 to generate an alarm interrupt every second, using the ESP8266.


Introduction

The objective of this post is to explain how to configure the DS3231 to generate an alarm interrupt every second, using the ESP8266.

The code for this tutorial is almost the same as the previous post, where is explained how to configure the DS3231 RTC to generate an alarm interrupt when the value of the seconds matched a pre-defined value. So, I will do a quicker explanation for this post and focus on the changes.

We will use the DS3231 libraries indicated here, which can be installed via library manager of the Arduino IDE. You can check how to install them in this previous tutorial.

We will assume the use of the DS3231 Real Time Clock integrated in an easy to use board, which can be bought at eBay for less than 1 euro.


The hardware

The connection diagram for this tutorial is illustrated in figure 1. We just need to connect the SCL and SDA pins (I2C) of the DS3231 module to the corresponding pins of the ESP8266.

Additionally, we need to connect the square wave / alarm pin (SQW) of the DS3231 to the GPIO of the ESP8266 where we want the interrupt to be triggered

esp8266-ds3231-connection-design

Figure 1 – Connection diagram.

If you are using a NodeMCU board, take into consideration that the board pins don’t correspond to the ESP8266 pins (check here the correct mapping). So, if you are using a NodeMCU, the correct pin mapping is the following:

  • GPIO5 = D1
  • GPIO4 = D2
  • GPIO 13 = D7

The code

First of all, we need to declare the libraries needed to interact with the RTC from the ESP8266. So, we need to include the RTC library mentioned in the introductory section and the Wire library, which implements the I2C protocol functionalities.

Then, we declare some global variables. One of them will allow to signal the main code that an interrupt has occurred. The other just holds the number of the interrupt pin. We also declare an object of class RtcDS3231, which provides access to all the functions of the DS3231 module.

#include <Wire.h>
#include <RtcDS3231.h>

const byte interruptPin = 13;
volatile bool alarm = 0;

RtcDS3231<TwoWire> rtcObject(Wire);

Our setup function will include some initializations. We will first start the serial port, so we can communicate the output of the program. We will also attach an interrupt service routine, called handleInterrupt, to the pin specified before in the global variable.

Then we will initialize the real time clock by calling the Begin method on the RtcDS3231 object declared previously. After that, we will set the time and date of the real time clock, so our alarms work.

Since we are not going to use it, we can disable the 32 kHz output pin of the clock with the Enable32kHzPin method, passing as input the value false.

Then, we need to specify that the square wave / alarm pin of the DS3231 will be working in alarm mode, since the same output pin is shared between different functionalities. To do so, we use the SetSquareWavePin method, which receives as input the mode in which the pin will operate. We want the DS3231SquareWavePin_ModeAlarmOne mode, which indicates that the pin will trigger when the alarm one of the RTC triggers.

rtcObject.Enable32kHzPin(false);
rtcObject.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmOne);

As can be seen in the datasheet of the DS3231, the Alarm 1 of the device is the only one which supports generating an interrupt once per second.

So, we will now configure the alarm to generate an interrupt once per second. To do so, we will use an object of class DS3231AlarmOne. It will have the settings we want to configure for alarm one.

The constructor for this class receives as input the day, the hour, the minute and the second. Additionally, it receives a control value to indicate how the alarm will operate.

In our case, since we want our alarm to trigger once per second, we will specify the DS3231AlarmOneControl_OncePerSecond for the control parameter. You can check here the other operating modes.

Although the constructor dictates that we need to pass all the values mentioned before, we can pass dummy values to the other parameters, since they are not going to be used.

DS3231AlarmOne alarm1(
    0,
    0,
    0,
    0,
    DS3231AlarmOneControl_OncePerSecond);

To set the alarm, we then call the SetAlarmOne method on the rtcObject variable and pass it the previously defined DS3231AlarmOne object, which we called alarm1.

We also call the LatchAlarmsTriggeredFlags method to guarantee that our interrupt alarm is clear on the RTC. This method must be called after an alarm is triggered or otherwise it will not trigger again.

rtcObject.SetAlarmOne(alarm1);
rtcObject.LatchAlarmsTriggeredFlags();

The remaining code will be the same of the previous post, which you can check for a detailed step by step explanation.

So, bellow is the complete code, which has the handling of the generated interrupts. The interrupts are handled by printing the current timestamp when an alarm triggers, and then by calling the LatchAlarmsTriggeredFlags, which allows the next alarm to generate an interrupt.

#include <Wire.h>
#include <RtcDS3231.h>

const byte interruptPin = 13;
volatile bool alarm = 0;

RtcDS3231<TwoWire> rtcObject(Wire);

void setup() {

  Serial.begin(115200);

  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING);

  rtcObject.Begin();

  RtcDateTime timestamp = RtcDateTime(__DATE__, __TIME__);
  rtcObject.SetDateTime(timestamp);

  rtcObject.Enable32kHzPin(false);
  rtcObject.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmOne);

  DS3231AlarmOne alarm1(
    0,
    0,
    0,
    0,
    DS3231AlarmOneControl_OncePerSecond);

  rtcObject.SetAlarmOne(alarm1);
  rtcObject.LatchAlarmsTriggeredFlags();

}

void loop() {

  if (alarm == true) {
    handleAlarm();
  }

}

void handleAlarm() {
  alarm = false;

  RtcDateTime timestamp = rtcObject.GetDateTime();

  Serial.print("time interrupt at: ");
  char time[10];

  sprintf(time, "%d:%d:%d",
          timestamp.Hour(),
          timestamp.Minute(),
          timestamp.Second()
         );
  Serial.println(time);

  rtcObject.LatchAlarmsTriggeredFlags();

}

void handleInterrupt() {
  alarm = true;
}


Testing the code

To test the code, just upload it to the ESP8266 and open the serial console of the Arduino IDE. You should get something similar to figure 2, which shows the timestamp which is printed with every alarm interrupt.

esp8266-ds3231-alarm-every-second

Figure 2 – Output of the program.

As can be seen, the interrupts are occurring every second, as we specified.


Related posts


Related content

9 thoughts on “ESP8266: DS3231 alarms once per second”

  1. planning to build an html paste editor meaning you build your code to colorise your codes meaning even when you are off editor, when you paste on html pages, the syntax gets colored . . . will take your codes as test case. will keep you updated

  2. planning to build an html paste editor meaning you build your code to colorise your codes meaning even when you are off editor, when you paste on html pages, the syntax gets colored . . . will take your codes as test case. will keep you updated

  3. #include
    #include
    #include
    #include
    #include
    const char* ssid = “***************”; //MODEM SSID
    const char* password = “*************”;
    WiFiServer server(80);
    ////////////////////////////////////////////////////
    int fan = 4; //fan moc
    int ZC = 10; //zero cross
    int sw = 11; //fan control switch
    ////////////////////////////////////////////////////
    int val1,value;
    int data11=0;
    int mobiledata,adcdata=0;
    int flag0,flag2;
    int data1,data12;
    int switchstate;
    int i;

    void setup() {
    // put your setup code here, to run once:
    Serial.begin(115200);
    delay(10);
    pinMode(A0, INPUT);
    //digitalWrite(sw, HIGH);
    pinMode(fan,OUTPUT);
    digitalWrite(fan, HIGH);
    pinMode(ZC, INPUT);
    digitalPinToInterrupt(ZC);
    Serial.print(“Connecting to “); //STATION MODE SETTING FROM MOBILE
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid,password);
    while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println(“Connection Failed! Rebooting…”);
    delay(5000);
    WiFi.beginSmartConfig();
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(“.”);
    Serial.println(WiFi.smartConfigDone());
    }
    }
    Serial.println(“”);
    Serial.println(“WiFi connected”);
    server.begin();
    }

    void loop() {
    // put your main code here, to run repeatedly:
    //client.println(“qbitronics”);
    val1 = analogRead(A0);
    Serial.println(val1);
    // client.println(“qbitronics”);
    /////////////////////////////////////////////////////////////////
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    WiFi.begin(ssid,password);
    }
    WiFiClient client = server.available();
    if (!client) {
    return;
    }
    // Wait until the client sends some data
    Serial.println(“new client”);
    while(!client.available()){
    delay(1);
    }
    // Read the first line of the request
    String b = client.readStringUntil(‘\r’);
    if (b.indexOf(“/”)!=-1)
    {
    String read1;
    read1=b;
    Serial.println(b);
    client.flush();
    return;
    }
    client.println(“qbitronics”);
    }

    void light()
    {
    int ii;
    int dimtime = (950*data11);
    float dimvalue=dimtime/1000;
    int dimmer=int(dimvalue);
    for(ii=0;ii<1000;ii++)
    {
    delayMicroseconds(dimmer);
    }
    digitalWrite(fan, LOW);
    delayMicroseconds(130);
    digitalWrite(fan, HIGH);
    detachInterrupt(ZC);
    }
    this is my coding here the problem is i read ADC value from ADC pin and client data from mobile only one hence ADC data or client data is reading at a time how i over come from this…………….
    pls help me…..

  4. #include
    #include
    #include
    #include
    #include
    const char* ssid = “***************”; //MODEM SSID
    const char* password = “*************”;
    WiFiServer server(80);
    ////////////////////////////////////////////////////
    int fan = 4; //fan moc
    int ZC = 10; //zero cross
    int sw = 11; //fan control switch
    ////////////////////////////////////////////////////
    int val1,value;
    int data11=0;
    int mobiledata,adcdata=0;
    int flag0,flag2;
    int data1,data12;
    int switchstate;
    int i;
    void setup() {
    // put your setup code here, to run once:
    Serial.begin(115200);
    delay(10);
    pinMode(A0, INPUT);
    //digitalWrite(sw, HIGH);
    pinMode(fan,OUTPUT);
    digitalWrite(fan, HIGH);
    pinMode(ZC, INPUT);
    digitalPinToInterrupt(ZC);
    Serial.print(“Connecting to “); //STATION MODE SETTING FROM MOBILE
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid,password);
    while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println(“Connection Failed! Rebooting…”);
    delay(5000);
    WiFi.beginSmartConfig();
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(“.”);
    Serial.println(WiFi.smartConfigDone());
    }
    }
    Serial.println(“”);
    Serial.println(“WiFi connected”);
    server.begin();
    }
    void loop() {
    // put your main code here, to run repeatedly:
    //client.println(“qbitronics”);
    val1 = analogRead(A0);
    Serial.println(val1);
    // client.println(“qbitronics”);
    /////////////////////////////////////////////////////////////////
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    WiFi.begin(ssid,password);
    }
    WiFiClient client = server.available();
    if (!client) {
    return;
    }
    // Wait until the client sends some data
    Serial.println(“new client”);
    while(!client.available()){
    delay(1);
    }
    // Read the first line of the request
    String b = client.readStringUntil(‘\r’);
    if (b.indexOf(“/”)!=-1)
    {
    String read1;
    read1=b;
    Serial.println(b);
    client.flush();
    return;
    }
    client.println(“qbitronics”);
    }
    void light()
    {
    int ii;
    int dimtime = (950*data11);
    float dimvalue=dimtime/1000;
    int dimmer=int(dimvalue);
    for(ii=0;ii<1000;ii++)
    {
    delayMicroseconds(dimmer);
    }
    digitalWrite(fan, LOW);
    delayMicroseconds(130);
    digitalWrite(fan, HIGH);
    detachInterrupt(ZC);
    }
    this is my coding here the problem is i read ADC value from ADC pin and client data from mobile only one hence ADC data or client data is reading at a time how i over come from this…………….
    pls help me…..

  5. Muhammad Imran Bin Danial

    Sir can u teach how to connect with esp8266, RTC DS3231, and relay with apps Blynk. I want to connect with blynk and alarm at a specific date. like after 14 days, the blynk will give the notifications. Plis sir help me with my project.

Leave a Reply

Discover more from techtutorialsx

Subscribe now to keep reading and get access to the full archive.

Continue reading