Go Down

Topic: DS3231SN setting alarm (Read 2720 times) previous topic - next topic

I have managed to set the time on my Chronodot DS3231SN with the aid of a couple of tutorials. What I would like to do is set the alarm output of the clock (INTCN) to wake up the Atmega 328 (via interrupt) so that it can perform a task and then go back to sleep. I can't find any code which shows how to set the alarm of the DS3231SN to activate when the hours, minutes and seconds match. Could anyone help please? My need is to sample air temperature once every hour. I can put the 328 to sleep so that it consumes about 28 micro amps, thus allowing a stand alone battery operation and this clock is a very good way of accurate time keeping as well as providing an external interrupt for the 328 chip.
 

el_supremo

For an alarm once an hour the easiest way is to use Alarm2 and set the minutes to zero. To do this set addresses B, C and D to 0x80. Then write 6 into the control register at address E. This will enable Alarm2 and also enables the alarm interrupt to be generated on the SQW pin.

Pete

el_supremo

Correction. That will interrupt every minute.
For an interrupt every hour, on the hour, you need to set register B to zero and registers C and D to 0x80. Then write 6 into register E.

Pete

Thanks for the info Pete. I guess I should have said in my first post that I know nothing about writing code so the means of doing what you said is at the moment beyond me. I have looked through the Maxim data sheet to try to match things up with what you have said but I am still lost. I looked through the code that I used for setting and reading the time but still can't make any sense of it. Would I be close with the following:-
#include "Wire.h"
#define DS1307_ADDRESS 0Bh
#define DS1307_ADDRESS 0Ch
#define DS1307_ADDRESS 0Dh
#define DS1307_ADDRESS 0Eh
                                                                        then after the void setup and void loop  enter the following:-
Wire.beginTransmission(DS1307_ADDRESS 0Bh);
Wire.send(0);
(DS1307_ADDRESS 0Ch);
Wire.send(0x80);
(DS1307_ADDRESS 0Dh);
Wire.send(0x80);
(DS1307_ADDRESS 0Eh);
Wire.send(6);
Wire.endTransmission ();
                                                                   I don't dare try sending this to the RTC in case I screw everything up but am I anywhere close?

el_supremo

Add this function to your sketch:
Code: [Select]

#define CLOCK_ADDRESS 0x68

void RTC_write_register(unsigned char reg,unsigned char value)
{
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(reg);
  Wire.write(value);
  Wire.endTransmission();
}


and then in your setup() function you can set the alarm like this:
Code: [Select]

  RTC_write_register(0x0B,0);
  RTC_write_register(0x0C,0x80);
  RTC_write_register(0x0D,0x80);
  RTC_write_register(0x0E,6);


Pete

macegr

When the Arduino wakes up because the alarm output pin is activated, you'll also need to clear the alarm register. Otherwise the Arduino will never wake up again, because the INTCN/SQW pin remains active until the alarm flag is cleared by the microcontroller.
Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

Thanks for the feedback both of you. So if I understand this right the cycle is as follows. The clock alarm wakes the 328, the 328 has to cancel it's interrupt then write to the clock to clear the alarm flag then read the external temperature sensor and store it to memory then reset the clock alarm and then reset it's own interrupt again, then go back to sleep. It's a shame the clock alarm duration can't be set when the alarm time is set. It would be nice to just get a 100 millisecond pulse from the clock to initiate the interrupt of the 328.
OK I will have a go at writing this sketch.
   Thanks again.

el_supremo

Quote
The clock alarm wakes the 328

Yes.

Quote
the 328 has to cancel it's interrupt

This is done without any software intervention.

Quote
then write to the clock to clear the alarm flag

Yes.

Quote
then read the external temperature sensor and store it to memory

Or whatever needs to be done.

Quote
then reset the clock alarm and then reset it's own interrupt again,

No. The alarm is already set. Unless you change it, the alarm will fire again in one hour (or whatever interval the alarm is set for). Once you set the alarm and attach the interrupt the only thing you have to do with respect to the alarm is clear the alarm flag when the interrupt wakes up the processor from sleep. You also do not do anything about detaching/attaching the interrupt once it has been set.

Quote
then go back to sleep

Yes.

Quote
It's a shame the clock alarm duration can't be set when the alarm time is set. It would be nice to just get a 100 millisecond pulse from the clock to initiate the interrupt of the 328.

I don't understand what you mean.

The basic structure of your code would be:
Code: [Select]

void clock_interrupt(void)
{
}

void setup(void)
{
1. Initialize the SPI library
2. Initialize the temperature sensor
3. Initialize the RTC alarm.
4. attach the clock_interrupt function to the alarm (presumably Arduino pin 2)
}

void loop(void)
{
1. go to sleep
2. reset the alarm flag
3. read the temperature and store it
}

Note that the clock interrupt function doesn't do anything. Once it returns from the interrupt the processor will be woken up and code execution will resume after the sleep.
After step 3 of the loop() is done you just return from the function. This will almost immediately bring you back into the loop function again where you will promptly go back to sleep until the clock alarm causes the next interrupt.

Pete

Thanks Pete, it's beginning to make sense now that you have explained a few things. I guess when the RTC alarm output has triggered the 328 into waking up, the 328 has to send code over the I2C to turn the alarm flag off. I was thinking that the 328 had to cancel it's interrupt in case it kept re-triggering itself from that point. I am still fuddled about the register addresses of the RTC. In the data sheet they are referred to as 07h, 08h, 0Dh etc but in a previous post you referred to RTC_write_register (0x0C,0x80) etc. I gather that the 0x means it's ASCII code but I can't work out how the last two characters 0C and 80 relate to the data sheet address codes. This is probably because it's the first time I have encountered it, only having done the basic Arduino tutorials previously.

el_supremo

0Ch and 0x0C are different ways of saying that the number 0C is hexadecimal. 0Ch is often used in datasheets whereas 0x0C is used in the C/C++ language.

Pete

I have added the alarm settings to the main time and date code. I think I have added it as you indicated in one of your previous posts. Everything loads OK, no error messages, and the serial monitor feeds back the right time but the alarm doesn't activate. I have had a multimeter and a scope on the INT/SQW pin but it always remains logic 0. This is the code that I have. Any idea why the alarm doesn't activate?


Code: [Select]

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h>
#include <SPI.h>
#include <RTClib.h>
#include <RTC_DS1307.h>
#define CLOCK_ADDRESS 0x68
        void RTC_write_register(unsigned char reg,unsigned char value)
{
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.send(reg);
  Wire.send(value);
  Wire.endTransmission();
}
RTC_DS1307 RTC;

void setup () {
 

    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
    DateTime now = RTC.now();
    DateTime compiled = DateTime(__DATE__, __TIME__);
    if (now.unixtime() < compiled.unixtime()) {
    Serial.println("RTC is older than compile time! Updating");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
RTC_write_register(0x0B,0);
  RTC_write_register(0x0C,0x80);
  RTC_write_register(0x0D,0x80);
  RTC_write_register(0x0E,6);

}
}

void loop () {
    DateTime now = RTC.now();
     
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
     

     
         
    Serial.println();
    delay(3000);
}





Go Up