Go Down

Topic: External RTC to wake Arduino up on interrupt (Read 6675 times) previous topic - next topic

whoru

Jul 03, 2015, 12:30 am Last Edit: Jul 03, 2015, 12:35 am by whoru
Hi.

I have got RTC DS3231 working pretty well. I set my RTC to send interrupt signal on int.0 (pin2) every full minute. Was working great, I had the LED switch ON/OFF every minute. I assumed here that interrupts are working and I can use it as interrupt to wake an Arduino up. Well not so much.

Must mention here that I am using:
This library for low power
and This library for DS3231.

As provided in an example from library and HERE I am told that I can wake up Arduino when pin is low.

What I would like to achieve is obviously to wake Arduino up on interrupt from DS3231 every minute.
Here is my code. Would appreciate any help on that.

Code: [Select]
// Using JChristensen library

#include <DS3232RTC.h>
#include <Time.h>
#include <Wire.h>
#include "LowPower.h"

tmElements_t tm;

time_t cvt_date(char const *date, char const *time)
{
    char s_month[5];
    int year;
    tmElements_t t;
    static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

    sscanf(date, "%s %hhd %d", s_month, &t.Day, &year);
    sscanf(time, "%2hhd %*c %2hhd %*c %2hhd", &t.Hour, &t.Minute, &t.Second);

    t.Month = (strstr(month_names, s_month) - month_names) / 3 + 1;
   
    /*
    if( year > 99)
      t.Year = year - 1970;
    else
      t.Year = year + 30;
    */
    t.Year = year - 1970;

    return makeTime(t);
}

int switchPin = 2;
int ledPin = 13;
boolean lastButton = LOW;
boolean ledOn = false;

void blink() {
  if (digitalRead(switchPin) == HIGH && lastButton == LOW) {
    ledOn = !ledOn;
    lastButton = HIGH;
  } else {
    lastButton = digitalRead(switchPin);
  }
  digitalWrite(ledPin, ledOn);
}

void pin2Interrupt(void)
{

}

void setup(void) {
  Serial.begin(9600);
  pinMode(ledPin,OUTPUT);
  pinMode(switchPin,INPUT);

  //attachInterrupt(0, pin2Interrupt, CHANGE);
 
  Serial.println(String("__DATE__ = ") + __DATE__);
  Serial.println(String("__TIME__ = ") + __TIME__);
 
  setTime(cvt_date(__DATE__, __TIME__));
  RTC.set(now());
  RTC.squareWave(SQWAVE_NONE);
  RTC.setAlarm(ALM2_EVERY_MINUTE,0,0,0);
  RTC.alarmInterrupt(ALARM_2, true);
 
  Serial.println(String("System date = ") + day() + "/" + month() + "/" + year() + " " + hour() + ":" + minute() + ":" + second() + "\n");

}

void loop(void) {
  //digitalClockDisplay(); //print time and date
  Serial.println("Entering sleep mode");
  delay(1000);
  attachInterrupt(0, pin2Interrupt, LOW);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  detachInterrupt(0);
}

void digitalClockDisplay(void)
{
  // digital clock display of the time
  RTC.read(tm);
  Serial.print(tm.Day,DEC);
  Serial.print('/');
  Serial.print(tm.Month, DEC);
  Serial.print('/');
  Serial.print(tm.Year+1970, DEC);
  Serial.print("   ");
  Serial.print(tm.Hour, DEC);
  Serial.print(':');
  Serial.print(tm.Minute, DEC);
  Serial.print(':');
  Serial.println(tm.Second, DEC);
 
  if (RTC.alarm(ALARM_2) ) {
    Serial.println("ALARM");
  }
}


I have 4.7k Ohm resistor between SQW and +5V.

nickgammon

Code: [Select]
  attachInterrupt(0, pin2Interrupt, LOW);


You are better off using FALLING than LOW.

Quote
Well not so much.
What is the problem? It doesn't sleep? It doesn't wake?
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

whoru

#2
Jul 03, 2015, 01:05 am Last Edit: Jul 03, 2015, 01:16 am by whoru
You are better off using FALLING than LOW.

What is the problem? It doesn't sleep? It doesn't wake?
MASSIVE EDIT : Wow. Nick you were right. Tried it with FALLING and it works like a charm. Thanks!

After Nick posted I got it working without 3rd party library like this but first code is neater:
Code: [Select]
#include <avr/sleep.h>
#include <avr/power.h>
#include <DS3232RTC.h>
#include <Time.h>
#include <Wire.h>

tmElements_t tm;

//CONVERT __DATE__ and __TIME__ to time_t
time_t cvt_date(char const *date, char const *time) {
    char s_month[5];
    int year;
    tmElements_t t;
    static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

    sscanf(date, "%s %hhd %d", s_month, &t.Day, &year);
    sscanf(time, "%2hhd %*c %2hhd %*c %2hhd", &t.Hour, &t.Minute, &t.Second);

    t.Month = (strstr(month_names, s_month) - month_names) / 3 + 1;
   
    /*
    if( year > 99)
      t.Year = year - 1970;
    else
      t.Year = year + 30;
    */
    t.Year = year - 1970;

    return makeTime(t);
}

int pin2 = 2;

void pin2Interrupt(void) {

  detachInterrupt(0);
}

void enterSleep(void) {
 
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(100);
 
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
  sleep_enable();
 
  sleep_mode();
 
  /* The program will continue from here. */
 
  /* First thing to do is disable sleep. */
  sleep_disable();
}

void setup() {
  Serial.begin(9600);
 
  /* Setup the pin direction. */
  pinMode(pin2, INPUT);
 
  setTime(cvt_date(__DATE__, __TIME__));
  RTC.set(now());
  RTC.squareWave(SQWAVE_NONE);
  RTC.setAlarm(ALM2_EVERY_MINUTE,0,0,0);
  RTC.alarmInterrupt(ALARM_2, true);
 
  Serial.println(String("System date = ") + day() + "/" + month() + "/" + year() + " " + hour() + ":" + minute() + ":" + second() + "\n");
 
  Serial.println("Initialisation complete.");
}

int seconds = 0;

void loop() {
  delay(1000);
  seconds++;
 
  Serial.print("Awake for ");
  Serial.print(seconds, DEC);
  Serial.println(" second");
  //digitalClockDisplay(); //print time and date
 
  if(seconds == 3) {
    Serial.println("Entering sleep");
    digitalClockDisplay();
    delay(200);
    seconds = 0;
    enterSleep();
  }
 
}

//PRINT TIME FROM RDS3231
void digitalClockDisplay(void) {
  // digital clock display of the time
  RTC.read(tm);
  Serial.print(tm.Day,DEC);
  Serial.print('/');
  Serial.print(tm.Month, DEC);
  Serial.print('/');
  Serial.print(tm.Year+1970, DEC);
  Serial.print("   ");
  Serial.print(tm.Hour, DEC);
  Serial.print(':');
  Serial.print(tm.Minute, DEC);
  Serial.print(':');
  Serial.println(tm.Second, DEC);
 
  if(RTC.alarm(ALARM_2)) {
    Serial.println("ALARM");
  }
}

jboyton

I read in the Atmega328 datasheet that for INT0 and INT1 only  a "level interrupt" will wake the processor. Why, then, is it waking on an edge interrupt?


nickgammon

See: http://www.gammon.com.au/interrupts

Confirmed by Atmel that the datasheet is wrong:

Quote
Commented by Manoraj Gnanadhas (Atmel)
2015-01-20 06:23:36 GMT
[Recipients: Nick Gammon]


Hello Nick,

Our design team has confirmed that "Note-3 mentioned under Table 10-1" is a datasheet bug. So you can use any type of interrupt (Rising edge/ Falling edge / Low level / Any logical change) to wake up from sleep mode. Sorry for the inconvenience caused.

Best Regards,
Manoraj Gnanadhas
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jboyton

#5
Jul 03, 2015, 02:33 am Last Edit: Jul 03, 2015, 05:40 pm by jboyton
Nice!

edit: So why doesn't a level interrupt work for him?

nickgammon

Level interrupts are problematic because they continue firing. Unlike an edge interrupt it keeps calling the ISR while the level is still LOW. This could cause the sketch to run extremely slowly until the interrupt is disabled.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jboyton

How did you know I edited this thread?

Is there an edge interrupt for forum thread edits that you had enabled?

nickgammon

#8
Jul 06, 2015, 11:32 pm Last Edit: Jul 06, 2015, 11:32 pm by Nick Gammon
Under each post it tells you if someone edited it:

Quote
Re: External RTC to wake Arduino up on interrupt
Jul 03, 2015, 10:33 am Last Edit: Jul 04, 2015, 01:40 am by jboyton
Or did you not mean that?
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

jboyton

#9
Jul 07, 2015, 12:45 am Last Edit: Jul 07, 2015, 12:46 am by jboyton
No, I meant how did you know to go back and look at this thread when it hadn't been replied to since your last post? Is there a notification mechanism for threads where a post is edited?

nickgammon

Ah, I see. As it happened I was searching for a thread that mentioned Manoraj Gnanadhas from Atmel, because of the issue of whether interrupts were triggered by a falling level or not. Having found this thread (for an unrelated reason to your edit) I noticed the edit and responded to it.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Go Up