How to wake up arduino by conditions

Hey guys!
I’m trying to wake up Arduino by the information from DS1307. The examples i found are using attachInterrupt. But i don’t want to wake up by the pins situation (change/high/low/high-to-low…). Is there any way to wake up by some condition?
Here’s the example i use !

#include <Enerlib.h>

Energy energy;             // 宣告"Energy"程式物件

const byte swPin = 2;      // 開關腳位
const byte ledPin = 13;    // LED腳位
byte times = 0;            // 記錄執行次數
volatile byte state = 0;   // 暫存執行狀態

void wakeISR() {
   if (energy.WasSleeping()) {
    state = 1;
  } else {
    state = 2;
  }
}

void setup() {
  Serial.begin(9600);
 
  pinMode(ledPin, OUTPUT);
  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);
 
  attachInterrupt(0, wakeISR, CHANGE);  // 附加中斷服務常式
  
  Serial.println("Running...");
}

void loop()
{
  if (state == 1) {
    Serial.println("Was sleeping...");
  } else if (state == 2) {
    Serial.println("Was awake...");
  }
  state = 0;
  
  digitalWrite(ledPin, !digitalRead(ledPin));
  delay(500);
  times ++;
  Serial.println(times);

  if (times > 5) {
    times = 0;
    Serial.println("Go to sleep...");
    energy.PowerDown();
  }
}

The only ways to wake from sleep are an external interrupt (pin changing state, either INT1/INT0 or PCINTs), or using the watchdog timer to wake periodically (note that the WDT doesn't keep very accurate time either)

The 1307 doesn't have a way to drive a pin high/low in response to some time-related event. The microcontroller cannot communicate over I2C while sleeping. So I think you'll need to use the WDT to periodically wake, and then interrogate the DS1307 to determine if anything needs to be done.

I think there exist some RTC chips that can drive a pin high or low at a specified time - but not the DS1307

Thanks DrAzzy !
Or should i use DS3232 which has the output to drive the pin change?
https://github.com/JChristensen/DS3232RTC
I thought that it may can be done by Timer interrupt!

Hello fxsh1301

The DUE board has a builtin RTT and RTC which provide programmable alarms. These (internal) can trigger a Wake up after a low power mode programming (backup or Wait ).

fxsh1301:
Or should i use DS3232 which has the output to drive the pin change?

I have not used the DS3232 but DS3231 several times.
With DS3231 you can set alarm times that can wake up a sleeping micro controller via external interrupt.
Once awake, the micro controller can do what it is supposed to do, after that set the next alarm time and go to sleep again. Alarm times can be intervals from seconds to days - it is very flexible.
So it is possible to make low current drawing designs, that work on battery power for a long time.

But keep in mind that “normal Arduino board” will draw relatively much current even if in sleep mode because of overhead for voltage regulator, usb driver chip and other.
A more “bare bones” design can reduce the power consumption to “almost nothing” during sleep.
For more information about power saving take a look at this great site: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors

Thanks uxomm!
Is there possible to make the DS3232 output periodically like twice a minute?
Because the RTC.setAlarm seems like a fixed parameter that can only allow 2 alarm time to set.
The project need to be interrupt by external periodically.

fxsh1301:
Is there possible to make the DS3232 output periodically like twice a minute?
Because the RTC.setAlarm seems like a fixed parameter that can only allow 2 alarm time to set.

It is the same with the alarm clock i have beside my bed: The alarm time is "fixed" in the sense it will not change by itself during the night (hopefully) but I can set (change) it as often as I want.

With the DS3231 you can do it like this (pseudo code):

wake up
x = read RTC time
do what is to do (should take less than 30 seconds)
set alarm time to x + 30 seconds
go to sleep

Hello uxomm! Thanks for your advice!
Im using DS3232 with this library ---> GitHub - Tecsmith/DS3232RTC: Arduino library for DS3232 RTC
But i got some error when i was compiling :fatal error: Streaming.h: No such file or directory
The library was imported by IDE, so i think it should properly installed.
And here's the circuit i wired, using 220 ohm and 220nf.

Imgur

I have never used bare bones RTC chips, but “breakout boards” and there are only a few additional components like resistors and condensers.
I have not used DS3232 but DS3231 but functionality is quite similar (beside the additional sram with 3232).

I am not sure if your wiring is correct.
I suspect that 220 Ohm at SCL and SDA is to low. I would use 4.7 kilo ohm (to 10 kilo ohm) as pullup resistors.

Maybe this RTC schematic can help how to wire the DS3232:

Error message: fatal error: Streaming.h: No such file or directory
Without knowing the sketch it is hard to guess why you get this error.
So post your code (using code tags).

Hello uxomm!
The code i used is from the DS3232 on Github, here’s the code:

/*----------------------------------------------------------------------*
 * Display the date and time from a DS3231 or DS3232 RTC every second.  *
 * Display the temperature once per minute. (The DS3231 does a          *
 * temperature conversion once every 64 seconds. This is also the       *
 * default for the DS3232.)                                             *
 *                                                                      *
 * Set the date and time by entering the following on the Arduino       *
 * serial monitor:                                                      *
 *    year,month,day,hour,minute,second,                                *
 *                                                                      *
 * Where                                                                *
 *    year can be two or four digits,                                   *
 *    month is 1-12,                                                    *
 *    day is 1-31,                                                      *
 *    hour is 0-23, and                                                 *
 *    minute and second are 0-59.                                       *
 *                                                                      *
 * Entering the final comma delimiter (after "second") will avoid a     *
 * one-second timeout and will allow the RTC to be set more accurately. *
 *                                                                      *
 * No validity checking is done, invalid values or incomplete syntax    *
 * in the input will result in an incorrect RTC setting.                *
 *                                                                      *
 * Jack Christensen 08Aug2013                                           *
 *                                                                      *
 * Tested with Arduino 1.0.5, Arduino Uno, DS3231/Chronodot, DS3232.    *
 *                                                                      *
 * This work is licensed under the Creative Commons Attribution-        *
 * ShareAlike 3.0 Unported License. To view a copy of this license,     *
 * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a       *
 * letter to Creative Commons, 171 Second Street, Suite 300,            *
 * San Francisco, California, 94105, USA.                               *
 *----------------------------------------------------------------------*/ 
 
#include <DS3232RTC.h>        //http://github.com/JChristensen/DS3232RTC
#include <Streaming.h>        //http://arduiniana.org/libraries/streaming/
#include <Time.h>             //http://playground.arduino.cc/Code/Time
#include <Wire.h>             //http://arduino.cc/en/Reference/Wire

void setup(void)
{
    Serial.begin(115200);
    
    //setSyncProvider() causes the Time library to synchronize with the
    //external RTC by calling RTC.get() every five minutes by default.
    setSyncProvider(RTC.get);
    Serial << F("RTC Sync");
    if (timeStatus() != timeSet) Serial << F(" FAIL!");
    Serial << endl;
}

void loop(void)
{
    static time_t tLast;
    time_t t;
    tmElements_t tm;

    //check for input to set the RTC, minimum length is 12, i.e. yy,m,d,h,m,s
    if (Serial.available() >= 12) {
        //note that the tmElements_t Year member is an offset from 1970,
        //but the RTC wants the last two digits of the calendar year.
        //use the convenience macros from Time.h to do the conversions.
        int y = Serial.parseInt();
        if (y >= 100 && y < 1000)
            Serial << F("Error: Year must be two digits or four digits!") << endl;
        else {
            if (y >= 1000)
                tm.Year = CalendarYrToTm(y);
            else    //(y < 100)
                tm.Year = y2kYearToTm(y);
            tm.Month = Serial.parseInt();
            tm.Day = Serial.parseInt();
            tm.Hour = Serial.parseInt();
            tm.Minute = Serial.parseInt();
            tm.Second = Serial.parseInt();
            t = makeTime(tm);
            RTC.set(t);        //use the time_t value to ensure correct weekday is set
            setTime(t);        
            Serial << F("RTC set to: ");
            printDateTime(t);
            Serial << endl;
            //dump any extraneous input
            while (Serial.available() > 0) Serial.read();
        }
    }
    
    t = now();
    if (t != tLast) {
        tLast = t;
        printDateTime(t);
        if (second(t) == 0) {
            float c = RTC.temperature() / 4.;
            float f = c * 9. / 5. + 32.;
            Serial << F("  ") << c << F(" C  ") << f << F(" F");
        }
        Serial << endl;
    }
}

//print date and time to Serial
void printDateTime(time_t t)
{
    printDate(t);
    Serial << ' ';
    printTime(t);
}

//print time to Serial
void printTime(time_t t)
{
    printI00(hour(t), ':');
    printI00(minute(t), ':');
    printI00(second(t), ' ');
}

//print date to Serial
void printDate(time_t t)
{
    printI00(day(t), 0);
    Serial << monthShortStr(month(t)) << _DEC(year(t));
}

//Print an integer in "00" format (with leading zero),
//followed by a delimiter character to Serial.
//Input value assumed to be between 0 and 99.
void printI00(int val, char delim)
{
    if (val < 10) Serial << '0';
    Serial << _DEC(val);
    if (delim > 0) Serial << delim;
    return;
}

The code below that can set and read the time, so i think the circuit is correct.
My goal is to make the DS3232 output the square wave.

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
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 setup()
{
  Wire.begin();
  Serial.begin(9600);
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
   //setDS3231time(20,8,15,1,8,1,17);
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void displayTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  // send it to the serial monitor
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print(" Day of week: ");
  switch(dayOfWeek){
  case 1:
    Serial.println("Sunday");
    break;
  case 2:
    Serial.println("Monday");
    break;
  case 3:
    Serial.println("Tuesday");
    break;
  case 4:
    Serial.println("Wednesday");
    break;
  case 5:
    Serial.println("Thursday");
    break;
  case 6:
    Serial.println("Friday");
    break;
  case 7:
    Serial.println("Saturday");
    break;
  }
}
void loop()
{
  displayTime(); // display the real-time clock data on the Serial Monitor,
  delay(1000); // every second
}

fxsh1301:
The code below that can set and read the time, so i think the circuit is correct.
My goal is to make the DS3232 output the square wave.

Good to hear that your hardware is working.
Nevertheless I think it is a good idea to change the resistors to 4.7 kilo ohm (220 to 4700 is factor 20) as 4.7 kilo ohm is a standard value for i2c lines pullups.

As attachment you will find the library I use with my RTC hardware. I had to change some lines of code of the library to get it work, there was a bug with alarm 2, but now it is fixed.
Actually it is for DS3231 but I am sure it will work for DS3232 also (as the working sketch you posted is for DS3231 also).

If you “install” the library you will find within the examples folder a sketch “DS3231_Alarm_Demo”. This sketch shows how to set alarm times and get a signal on SQW line every 30 seconds.
I made many comments so I hope it can help you.

To get alarm signal on SQW of RTC:
Pull up the SQW pin with 10 kilo ohm resistor to Vcc.
As an alternative you can use the internal pullup resistor of an Arduino pin (this is done in the sketch mentioned).
SQW line will go low (for about 1 second) when alarm time matches.

Connect SQW line of RTC to Arduino Pin D2.
Internal LED (D13) will go on, while SQW is low (this will be every 30 seconds).

DS3231.zip (10.2 KB)