I have a DS3234 RTC configured to trigger an alarm every 5 minutes to wake up the Arduino, the problem is that the interrupt on pin 2 appears to freeze completely the Arduino, if I don't sleep the arduiuno also be blocked when interrupt is activated, somebody can help me?
The code is:
#include <SPI.h>
#include "ds3234.h"
#include "Enerlib.h"
#define BUFF_MAX 256
const int cs = 8; // chip select pin
uint8_t sleep_period = 5; // the sleep interval in minutes between 2 consecutive alarms
Energy energy;
// how often to refresh the info on stdout (ms)
//unsigned long prev = 5000, interval = 5000;
void set_next_alarm(void)
{
struct ts t;
unsigned char wakeup_min;
DS3234_get(cs, &t);
// calculate the minute when the next alarm will be triggered
wakeup_min = (t.min / sleep_period + 1) * sleep_period;
if (wakeup_min > 59) {
wakeup_min -= 60;
}
// flags define what calendar component to be checked against the current time in order
// to trigger the alarm
// A2M2 (minutes) (0 to enable, 1 to disable)
// A2M3 (hour) (0 to enable, 1 to disable)
// A2M4 (day) (0 to enable, 1 to disable)
// DY/DT (dayofweek == 1/dayofmonth == 0)
boolean flags[4] = { 0, 1, 1, 1 };
// set Alarm2. only the minute is set since we ignore the hour and day component
DS3234_set_a2(cs, wakeup_min, 0, 0, flags);
// activate Alarm2
DS3234_set_creg(cs, DS3234_INTCN | DS3234_A2IE);
}
void INT0_ISR(void)
{
/*
The WasSleeping function will return true if Arduino
was sleeping before the IRQ. Subsequent calls to
WasSleeping will return false until Arduino reenters
in a low power state. The WasSleeping function should
only be called in the ISR.
*/
detachInterrupt(0);
/*
set_next_alarm();
// clear a2 alarm flag and let INT go into hi-z
DS3234_clear_a2f(cs);
*/
Serial.println(" Entering interrupt 0");
if (energy.WasSleeping())
{
/*
Arduino was waked up by IRQ.
If you shut down external peripherals before sleeping, you
can reinitialize them here. Look on ATMega's datasheet for
hardware limitations in the ISR when microcontroller just
leave any low power state.
*/
Serial.println(" Interrupt and was sleeping");
}
else
{
/*
The IRQ happened in awake state.
This code is for the "normal" ISR.
*/
Serial.println(" Interrupt and was NOT sleeping");
}
Serial.println(" Exiting interrupt 0");
}
void setup()
{
Serial.begin(9600);
Serial.println("Entering setup");
pinMode(2, INPUT);
delay(5000);
DS3234_init(cs, DS3234_INTCN);
DS3234_clear_a2f(cs);
set_next_alarm();
attachInterrupt(0, INT0_ISR, LOW);
}
void loop()
{
Serial.println("Entering loop");
delay(5000);
Serial.println("Powering down");
energy.PowerDown();
/*
char buff[BUFF_MAX];
struct ts t;
DS3234_get(cs, &t);
// display current time
snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year, t.mon, t.mday, t.hour, t.min, t.sec);
Serial.println(buff);
*/
}
Hello Mark,
I rewrite my code, and the problems is the same.
Code:
#include <SPI.h>
#include "ds3234.h"
#include "Enerlib.h"
#define BUFF_MAX 256
const int cs = 8; // chip select pin
uint8_t sleep_period = 5; // the sleep interval in minutes between 2 consecutive alarms
Energy energy;
int time_interrupt=0;
// how often to refresh the info on stdout (ms)
//unsigned long prev = 5000, interval = 5000;
void set_next_alarm(void)
{
struct ts t;
unsigned char wakeup_min;
DS3234_get(cs, &t);
// calculate the minute when the next alarm will be triggered
wakeup_min = (t.min / sleep_period + 1) * sleep_period;
if (wakeup_min > 59) {
wakeup_min -= 60;
}
// flags define what calendar component to be checked against the current time in order
// to trigger the alarm
// A2M2 (minutes) (0 to enable, 1 to disable)
// A2M3 (hour) (0 to enable, 1 to disable)
// A2M4 (day) (0 to enable, 1 to disable)
// DY/DT (dayofweek == 1/dayofmonth == 0)
boolean flags[4] = { 0, 1, 1, 1 };
// set Alarm2. only the minute is set since we ignore the hour and day component
DS3234_set_a2(cs, wakeup_min, 0, 0, flags);
// activate Alarm2
DS3234_set_creg(cs, DS3234_INTCN | DS3234_A2IE);
}
void INT0_ISR(void)
{
/*
The WasSleeping function will return true if Arduino
was sleeping before the IRQ. Subsequent calls to
WasSleeping will return false until Arduino reenters
in a low power state. The WasSleeping function should
only be called in the ISR.
*/
//detachInterrupt(0);
time_interrupt=1;
}
void setup()
{
Serial.begin(9600);
Serial.println("Entering setup");
pinMode(2, INPUT);
delay(5000);
DS3234_init(cs, DS3234_INTCN);
DS3234_clear_a2f(cs);
set_next_alarm();
attachInterrupt(0, INT0_ISR, LOW);
}
void loop()
{
if(time_interrupt==1){
Serial.println("time_interrupt==1");
time_interrupt=0;
if (energy.WasSleeping())
{
Serial.println(" Interrupt and was sleeping");
}
else
{
/*
The IRQ happened in awake state.
This code is for the "normal" ISR.
*/
Serial.println(" Interrupt and was NOT sleeping");
}
}
Serial.println("Entering loop");
delay(1000);
//Serial.println("Powering down");
//energy.PowerDown();
char buff[BUFF_MAX];
struct ts t;
DS3234_get(cs, &t);
// display current time
snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year, t.mon, t.mday, t.hour, t.min, t.sec);
Serial.println(buff);
}
I can't see if you are doing this, but when an alarm occurs you must clear the INTCN bit (bit 2) in the control register to reset it ready for the next alarm. You would do this in the loop() function each time that time_interrupt is set.
I also think it would be a lot easier to just set the alarm to interrupt every minute. You then initialize a counter to sleep_period and count it down on each interrupt until it reaches zero. That would avoid having to calculate the next value required for the alarm.
I need an alarm that wake up the Arduino every 5 minutes or more.
Code:
#include <SPI.h>
#include "ds3234.h"
#include "Enerlib.h"
#define BUFF_MAX 256
const int cs = 8; // chip select pin
uint8_t sleep_period = 5; // the sleep interval in minutes between 2 consecutive alarms
Energy energy;
int time_interrupt=0;
void set_next_alarm(void)
{
struct ts t;
unsigned char wakeup_min;
DS3234_get(cs, &t);
// calculate the minute when the next alarm will be triggered
wakeup_min = (t.min / sleep_period + 1) * sleep_period;
if (wakeup_min > 59) {
wakeup_min -= 60;
}
// flags define what calendar component to be checked against the current time in order
// to trigger the alarm
// A2M2 (minutes) (0 to enable, 1 to disable)
// A2M3 (hour) (0 to enable, 1 to disable)
// A2M4 (day) (0 to enable, 1 to disable)
// DY/DT (dayofweek == 1/dayofmonth == 0)
boolean flags[4] = { 0, 1, 1, 1 };
// set Alarm2. only the minute is set since we ignore the hour and day component
DS3234_set_a2(cs, wakeup_min, 0, 0, flags);
// activate Alarm2
DS3234_set_creg(cs, DS3234_INTCN | DS3234_A2IE);
}
void INT0_ISR(void)
{
//detach interrupt and set time_interrupt=1
//interrupt must be attached again
detachInterrupt(0);
time_interrupt=1;
}
void setup()
{
Serial.begin(9600);
Serial.println("Entering setup");
pinMode(2, INPUT);
delay(5000);
DS3234_init(cs, DS3234_INTCN);
DS3234_clear_a2f(cs);
set_next_alarm();
attachInterrupt(0, INT0_ISR, LOW);
}
void loop()
{
if(time_interrupt==1){
Serial.println(" time_interrupt==1");
time_interrupt=0;
// set next alarm
set_next_alarm();
// clear a2 alarm flag and let INT go into hi-z
DS3234_clear_a2f(cs);
//Attach interrupt again
attachInterrupt(0, INT0_ISR, LOW);
if (energy.WasSleeping())
{
Serial.println(" Interrupt and was sleeping");
}
else
{
/*
The IRQ happened in awake state.
This code is for the "normal" ISR.
*/
Serial.println(" Interrupt and was NOT sleeping");
}
}
Serial.println("Entering loop");
delay(1000);
/*
//For debuf only
char buff[BUFF_MAX];
struct ts t;
DS3234_get(cs, &t);
// display current time
snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year, t.mon, t.mday, t.hour, t.min, t.sec);
Serial.println(buff);
*/
Serial.println("Powering down");
energy.PowerDown();
}