Site icon techtutorialsx

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

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:

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.

Figure 2 – Output of the program.

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


Related posts


Related content

Exit mobile version