DS3231 time module - alarm interrupt not working

I'm making an alarm clock with the DS3231 precision time module. Setting the time works fine, but I'd like to trigger an alarm for a certain combination of hours, minutes and seconds (so just for a given time , the day doesn't matter).
I've been trying for a loooong time to get this to work, but it still doesn't work and does weird stuff sometimes.

I wrote a code to show you what I'm doing:

#include <Wire.h>

byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}


void setAlarm1(byte second, byte minute, byte hour)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(0x68);
  Wire.write(0x07); //alarm second location
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.endTransmission();
}

void setup()
{

  Serial.begin(9600);
  Wire.beginTransmission(0x68);   
  Wire.write(0x0F);               
  Wire.write(0b00000000);    //set flag from alarm1 to 0       
  Wire.endTransmission();
  
  Wire.beginTransmission(0x68);
  Wire.write(0x0E);
  Wire.write(0b00000101); //set INTCN to 1, set alarm interrupt enabled
  Wire.endTransmission();
  
  Wire.beginTransmission(0x68);
  Wire.write(0x0A);
  Wire.write(0b10000000); //set A1M4 to 1 so that the alarm reacts on hours, minutes and seconds
  Wire.endTransmission();
  
  setAlarm1(0,41,21);
  attachInterrupt(0,functie,RISING);
}

void loop()
{
  Wire.beginTransmission(0x68);
  Wire.write(0x0F);
  Wire.endTransmission();
  Wire.requestFrom(0x68,1);
  byte data = Wire.read();
  delay(15);
  Serial.println(data,BIN);
  delay(1000);
}

void functie()
{
 Serial.println("alarm"); 
}

Here is the datasheet: http://datasheets.maximintegrated.com/en/ds/DS3231.pdf

The output:
A lot of interrupts every cyclus and I read 11111111 from the register every cyclus...
Can any of you guys figure out what I'm doing wrong?

Can any of you guys figure out what I'm doing wrong?

Add Wire.begin() first thing to your setup.

Hello,

  • The interrupt must be set to FALLING instead of RISING, and the interrupt pin must be set to INPUT_PULLUP mode
pinMode( 2, INPUT_PULLUP );
attachInterrupt( digitalPinToInterrupt( 2 ), functie, FALLING );
  • After the alarm is triggered, you have to clear the alarm flag (A1F in the Status register) yourself.

  • Also, you should not use Serial.print or other slow operations inside an ISR. Read more about that here

Edit: huge mistake corrected :-[

cattledog:
Add Wire.begin() first thing to your setup.

I saw that too and came back to this post to correct it. You were ahead of me, thanks! This resolves the only 11111111 readings, so I can read the actual values that I wrote to the specific register.

guix:
Hello,

  • The interrupt must be set to FALLING instead of RISING, and the interrupt pin must be set to INPUT_PULLUP mode Thanks, I changed it in my code
pinMode( INT0, INPUT_PULLUP );

attachInterrupt( 0, functie, FALLING );




- After the alarm is triggered, you have to clear the alarm flag (A1F in the Status register) yourself. done, thanks

- Also, you should not use Serial.print or other slow operations inside an ISR. Read more about that [here](http://gammon.com.au/interrupts) I set a flag now in my code and check it in the loop

Well, now the alarm partly works: the alarm changes the A1F from 0 to 1 when it's time, but the interrupt is still going crazy (I get like 30 interrupts per second, and that doesn't change when I deconnect the wire...)

So the code that I used to read the register without interrupt (they are commented out)

#include <Wire.h>
int alarmflag = 0;

byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}


void setAlarm1(byte second, byte minute, byte hour)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(0x68);
  Wire.write(0x07); //alarm second location
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.endTransmission();
}

void setup()
{

  Wire.begin();
  Serial.begin(9600);
  Wire.beginTransmission(0x68);   
  Wire.write(0x0F);               
  Wire.write(0b00000000);    //set flag from alarm1 to 0       
  Wire.endTransmission();
  
  Wire.beginTransmission(0x68);
  Wire.write(0x0E);
  Wire.write(0b00000101); //set INTCN to 1, set alarm interrupt enabled
  Wire.endTransmission();
  
  Wire.beginTransmission(0x68);
  Wire.write(0x0A);
  Wire.write(0b10000000); //set A1M4 to 1 so that the alarm reacts on hours, minutes and seconds
  Wire.endTransmission();
  
  setAlarm1(0,11,11);
  //pinMode( INT0, INPUT_PULLUP );
  //attachInterrupt(0,functie,FALLING);
}

void loop()
{
  Wire.beginTransmission(0x68);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(0x68,3);
  byte s = Wire.read();
  byte m = Wire.read();
  byte h = Wire.read();
  s = bcdToDec(s);
  m = bcdToDec(m);
  h = bcdToDec(h);
  Serial.print(h);Serial.print(':');Serial.print(m); Serial.print(':');Serial.println(s);
  Serial.print("register status: ");
  Wire.beginTransmission(0x68);
  Wire.write(0x0F);
  Wire.endTransmission();
  Wire.requestFrom(0x68,1);
  byte data = Wire.read();
  delay(15);
  Serial.println(data,BIN);
  /*if(alarmflag == 1)
  {
   alarmflag=0;
   Serial.println("Alarm!");
   Wire.begin();
  Serial.begin(9600);
  Wire.beginTransmission(0x68);   
  Wire.write(0x0F);               
  Wire.write(0b00000000);    //set flag from alarm1 to 0       
  Wire.endTransmission();
   
  }*/
  delay(1000);
}

/*void functie()
{
 alarmflag = 1;
}*/

When I actually use the code that is commented out (the interrupt code), the following happens:

  • I get the notification 'Alarm!' every second in my serial monitor
  • When the time on the module matches the time on the alarm everything stops working (nothing happens in the Serial monitor)
  • When I remove the wire, everything works again. I can see one time that the alarm trigger bit is set to 1 and then it is set back to 0. So this makes me think that the module really stops sending data while the interrupt wire is connected.

Just did some more testing.

  • The interrupt gets triggered as much when the interrupt pin 0 is connected to the DS3231 as when it's not.
  • The problem of the DS3231 stopping sending data when the alarm is triggered, doesn't only happen when the interrupt pin is connected to the DS3231, but just when a pin from the arduino is connected to the interrupt output of the ds3231. When I remove the cable it works fine.

Remove the serial print from the interrupt routine and get back to us.

The latest posted code works fine for me. Here are the register values after uploading our code with the alarm values 11,11,11. I can see the flag set and the "Alarm!" printed on a match.

Register Bit Values

0X00 00010011
0X01 01000100
0X02 00001000
0X03 00000100
0X04 00011001
0X05 00001000
0X06 00010101
0X07 00010001
0X08 00010001
0X09 00010001
0X0A 10000000
0X0B 00000000
0X0C 00000000
0X0D 00000000
0X0E 00000101
0X0F 00000000

Your problem sounds like hardware to me. Are you using a module or the bare DS3231. My module is a ZS 042 and it has a built in pullup on the sqw/alarm output.

Thank you very much for testing Cattledog! I've been searching for hours on what might be wrong with the code/module. Thanks to you I had the idea of trying on an Arduino nano instead of my Leonardo and now it worked perfectly. I'll take a look whether my Leonardo is broken or not.

And thx giux for making my code better/work! I really appreciate it!

+karma of course for both :slight_smile:

Good :wink:

Maybe you know that already: the interrupt 0 on the Leonardo is on pin 3, unlike most others arduino where it's on pin 2.

guix:
Good :wink:

Maybe you know that already: the interrupt 0 on the Leonardo is on pin 3, unlike most others arduino where it's on pin 2.

Yeah I do know that. I really can't figure out why this is working on 1 arduino and not on the other. My interrupts on my Leonardo seem to be working fine, I tested them with a simple button program.
It kinda annoys me, I hope I'll find a way around...
The original plan was using my Nano for this project but there are only 2 interrupts on there.
Then I thought about using the Micro, but there are 2 interrupts on the same pins as the i2c SDA and SCL :frowning:
So yeah guess I'm stuck with a Leonardo or an interrupt expander.

Do you really need interrupts? You could also just poll the A1F flag in your main loop.

Rather than banging on the i2c bus to read A1F every pass through the loop I would recommend polling the alarm output. The wire which you are taking from the INT/SQW output pin on the RTC to the int 0 pin on the Leonardo can be polled on any digital input. When the alarm is triggered, this output is latched until the A1F status flag is cleared.

I highly recommend the DS3231RTC libray by JChristensen GitHub - JChristensen/DS3232RTC: Arduino Library for Maxim Integrated DS3232 and DS3231 Real-Time Clocks and the TimeAlrms library found here, TimeAlarms Library, Run Functions At Specific Times

Those got me out of a spot, the libraries and the folks here :slight_smile:

guix:
Do you really need interrupts? You could also just poll the A1F flag in your main loop.

Yeah I do. I didn't tell it in the post but I want to wake the Arduino up when the alarm goes off or when motion is detecten, because an alarm clock doesn't have to be doing anything while I'm away or while I'm sleeping. So the Arduino will sleep then too.

cattledog:
Rather than banging on the i2c bus to read A1F every pass through the loop I would recommend polling the alarm output. The wire which you are taking from the INT/SQW output pin on the RTC to the int 0 pin on the Leonardo can be polled on any digital input. When the alarm is triggered, this output is latched until the A1F status flag is cleared.

So this won't work too.
But I(ve though about the problem and now I realise that I can perfectly manage the menu with a rotary encoder and the button in the rotary encoder without using interrupts for those.
So now, I have enough interrupts on the nano (one for the motion sensor and one for the alarm).
Thanks! Again +karma for both :smiley:

Gibz73:
I highly recommend the DS3231RTC libray by JChristensen GitHub - JChristensen/DS3232RTC: Arduino Library for Maxim Integrated DS3232 and DS3231 Real-Time Clocks and the TimeAlrms library found here, TimeAlarms Library, Run Functions At Specific Times

Those got me out of a spot, the libraries and the folks here :slight_smile:

I might be powering the Arduino completely off during the day, so this isn't really an option then. But thanks :slight_smile: