From cb7bd533cb2b505441ca9a35c9897db358a30b47 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Tue, 20 Mar 2012 23:25:17 +1300 Subject: Add Time library Signed-off-by: Mike Beattie --- .../Examples/TimeAlarmExample/TimeAlarmExample.pde | 77 ++++++++ TimeAlarms/TimeAlarms.cpp | 150 ++++++++++++++ TimeAlarms/TimeAlarms.h | 127 ++++++++++++ TimeAlarms/keywords.txt | 25 +++ TimeAlarms/readme.txt | 220 +++++++++++++++++++++ 5 files changed, 599 insertions(+) create mode 100644 TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde create mode 100644 TimeAlarms/TimeAlarms.cpp create mode 100644 TimeAlarms/TimeAlarms.h create mode 100644 TimeAlarms/keywords.txt create mode 100644 TimeAlarms/readme.txt (limited to 'TimeAlarms') diff --git a/TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde b/TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde new file mode 100644 index 0000000..5084ffd --- /dev/null +++ b/TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde @@ -0,0 +1,77 @@ +/* + * TimeAlarmExample.pde + * + * This example calls alarm functions at 8:30 am and at 5:45 pm (17:45) + * and simulates turning lights on at night and off in the morning + * A weekly timer is set for Saturdays at 8:30:30 + * + * A timer is called every 15 seconds + * Another timer is called once only after 10 seconds + * + * At startup the time is set to Jan 1 2011 8:29 am + */ + +#include +#include + +void setup() +{ + Serial.begin(9600); + setTime(8,29,0,1,1,11); // set time to Saturday 8:29:00am Jan 1 2011 + // create the alarms + Alarm.alarmRepeat(8,30,0, MorningAlarm); // 8:30am every day + Alarm.alarmRepeat(17,45,0,EveningAlarm); // 5:45pm every day + Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm); // 8:30:30 every Saturday + + + Alarm.timerRepeat(15, Repeats); // timer for every 15 seconds + Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds +} + +void loop(){ + digitalClockDisplay(); + Alarm.delay(1000); // wait one second between clock display +} + +// functions to be called when an alarm triggers: +void MorningAlarm(){ + Serial.println("Alarm: - turn lights off"); +} + +void EveningAlarm(){ + Serial.println("Alarm: - turn lights on"); +} + +void WeeklyAlarm(){ + Serial.println("Alarm: - its Monday Morning"); +} + +void ExplicitAlarm(){ + Serial.println("Alarm: - this triggers only at the given date and time"); +} + +void Repeats(){ + Serial.println("15 second timer"); +} + +void OnceOnly(){ + Serial.println("This timer only triggers once"); +} + +void digitalClockDisplay() +{ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.println(); +} + +void printDigits(int digits) +{ + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + diff --git a/TimeAlarms/TimeAlarms.cpp b/TimeAlarms/TimeAlarms.cpp new file mode 100644 index 0000000..66b94f9 --- /dev/null +++ b/TimeAlarms/TimeAlarms.cpp @@ -0,0 +1,150 @@ +/* + TimeAlarms.cpp - Arduino Time alarms for use with Time library + Copyright (c) 208-2011 Michael Margolis. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + /* + 2 July 2011 - replaced alarm types implied from alarm value with enums to make trigger logic more robust + - this fixes bug in repeating weekly alarms - thanks to Vincent Valdy and draythomp for testing +*/ + +extern "C" { +#include // for memset +} + +#include +#include "TimeAlarms.h" +#include "Time.h" + +#define IS_ONESHOT true // constants used in arguments to create method +#define IS_REPEAT false + + +//************************************************************** +//* Alarm Class Constructor + +AlarmClass::AlarmClass() +{ + Mode.isEnabled = Mode.isOneShot = 0; + Mode.alarmType = dtNotAllocated; + value = nextTrigger = 0; + onTickHandler = NULL; // prevent a callback until this pointer is explicitly set +} + +//************************************************************** +//* Private Methods + + +void AlarmClass::updateNextTrigger() +{ + if( (value != 0) && Mode.isEnabled ) + { + time_t time = now(); + if( dtIsAlarm(Mode.alarmType) && nextTrigger <= time ) // update alarm if next trigger is not yet in the future + { + if(Mode.alarmType == dtExplicitAlarm ) // is the value a specific date and time in the future + { + nextTrigger = value; // yes, trigger on this value + } + else if(Mode.alarmType == dtDailyAlarm) //if this is a daily alarm + { + if( value + previousMidnight(now()) <= time) + { + nextTrigger = value + nextMidnight(time); // if time has passed then set for tomorrow + } + else + { + nextTrigger = value + previousMidnight(time); // set the date to today and add the time given in value + } + } + else if(Mode.alarmType == dtWeeklyAlarm) // if this is a weekly alarm + { + if( (value + previousSunday(now())) <= time) + { + nextTrigger = value + nextSunday(time); // if day has passed then set for the next week. + } + else + { + nextTrigger = value + previousSunday(time); // set the date to this week today and add the time given in value + } + } + else // its not a recognized alarm type - this should not happen + { + Mode.isEnabled = 0; // Disable the alarm + } + } + if( Mode.alarmType == dtTimer) + { + // its a timer + nextTrigger = time + value; // add the value to previous time (this ensures delay always at least Value seconds) + } + } + else + { + Mode.isEnabled = 0; // Disable if the value is 0 + } +} + +//************************************************************** +//* Time Alarms Public Methods + +TimeAlarmsClass::TimeAlarmsClass() +{ + isServicing = false; + for(uint8_t id = 0; id < dtNBR_ALARMS; id++) + free(id); // ensure all Alarms are cleared and available for allocation +} + +// this method creates a trigger at the given absolute time_t +// it replaces the call to alarmOnce with values greater than a week +AlarmID_t TimeAlarmsClass::triggerOnce(time_t value, OnTick_t onTickHandler){ // trigger once at the given time_t + if( value > 0) + return create( value, onTickHandler, IS_ONESHOT, dtExplicitAlarm ); + else + return dtINVALID_ALARM_ID; // dont't allocate if the time is greater than one day +} + +// this method will now return an error if the value is greater than one day - use DOW methods for weekly alarms +AlarmID_t TimeAlarmsClass::alarmOnce(time_t value, OnTick_t onTickHandler){ // trigger once at the given time of day + if( value <= SECS_PER_DAY) + return create( value, onTickHandler, IS_ONESHOT, dtDailyAlarm ); + else + return dtINVALID_ALARM_ID; // dont't allocate if the time is greater than one day +} + +AlarmID_t TimeAlarmsClass::alarmOnce(const int H, const int M, const int S,OnTick_t onTickHandler){ // as above with HMS arguments + return create( AlarmHMS(H,M,S), onTickHandler, IS_ONESHOT, dtDailyAlarm ); +} + +AlarmID_t TimeAlarmsClass::alarmOnce(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler){ // as above, with day of week + return create( (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S), onTickHandler, IS_ONESHOT, dtWeeklyAlarm ); +} + +// this method will now return an error if the value is greater than one day - use DOW methods for weekly alarms +AlarmID_t TimeAlarmsClass::alarmRepeat(time_t value, OnTick_t onTickHandler){ // trigger daily at the given time + if( value <= SECS_PER_DAY) + return create( value, onTickHandler, IS_REPEAT, dtDailyAlarm ); + else + return dtINVALID_ALARM_ID; // dont't allocate if the time is greater than one day } AlarmID_t TimeAlarmsClass::alarmRepeat(const int H, const int M, const int S, OnTick_t onTickHandler){ // as above with HMS arguments return create( AlarmHMS(H,M,S), onTickHandler, IS_REPEAT, dtDailyAlarm ); } AlarmID_t TimeAlarmsClass::alarmRepeat(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler){ // as above, with day of week return create( (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S), onTickHandler, IS_REPEAT, dtWeeklyAlarm ); } AlarmID_t TimeAlarmsClass::timerOnce(time_t value, OnTick_t onTickHandler){ // trigger once after the given number of seconds return create( value, onTickHandler, IS_ONESHOT, dtTimer ); } AlarmID_t TimeAlarmsClass::timerOnce(const int H, const int M, const int S, OnTick_t onTickHandler){ // As above with HMS arguments return create( AlarmHMS(H,M,S), onTickHandler, IS_ONESHOT, dtTimer ); } AlarmID_t TimeAlarmsClass::timerRepeat(time_t value, OnTick_t onTickHandler){ // trigger after the given number of seconds continuously return create( value, onTickHandler, IS_REPEAT, dtTimer); } AlarmID_t TimeAlarmsClass::timerRepeat(const int H, const int M, const int S, OnTick_t onTickHandler){ // trigger after the given number of seconds continuously return create( AlarmHMS(H,M,S), onTickHandler, IS_REPEAT, dtTimer); } void TimeAlarmsClass::enable(AlarmID_t ID) { if(isAllocated(ID)) { Alarm[ID].Mode.isEnabled = (Alarm[ID].value != 0) && (Alarm[ID].onTickHandler != 0) ; // only enable if value is non zero and a tick handler has been set Alarm[ID].updateNextTrigger(); // trigger is updated whenever this is called, even if already enabled } } void TimeAlarmsClass::disable(AlarmID_t ID) { if(isAllocated(ID)) Alarm[ID].Mode.isEnabled = false; } // write the given value to the given alarm void TimeAlarmsClass::write(AlarmID_t ID, time_t value) { if(isAllocated(ID)) { Alarm[ID].value = value; enable(ID); // update trigger time } } // return the value for the given alarm ID time_t TimeAlarmsClass::read(AlarmID_t ID) { if(isAllocated(ID)) return Alarm[ID].value ; else return dtINVALID_TIME; } // return the alarm type for the given alarm ID dtAlarmPeriod_t TimeAlarmsClass::readType(AlarmID_t ID) { if(isAllocated(ID)) return (dtAlarmPeriod_t)Alarm[ID].Mode.alarmType ; else return dtNotAllocated; } + void TimeAlarmsClass::free(AlarmID_t ID) + { + if(isAllocated(ID)) + { + Alarm[ID].Mode.isEnabled = false; + Alarm[ID].Mode.alarmType = dtNotAllocated; + Alarm[ID].onTickHandler = 0; + Alarm[ID].value = 0; + Alarm[ID].nextTrigger = 0; + } + } + // returns the number of allocated timers uint8_t TimeAlarmsClass::count() { uint8_t c = 0; for(uint8_t id = 0; id < dtNBR_ALARMS; id++) { if(isAllocated(id)) c++; } return c; } // returns true only if id is allocated and the type is a time based alarm, returns false if not allocated or if its a timer bool TimeAlarmsClass::isAlarm(AlarmID_t ID) { return( isAllocated(ID) && dtIsAlarm(Alarm[ID].Mode.alarmType) ); } // returns true if this id is allocated bool TimeAlarmsClass::isAllocated(AlarmID_t ID) { return( ID < dtNBR_ALARMS && Alarm[ID].Mode.alarmType != dtNotAllocated ); } AlarmID_t TimeAlarmsClass::getTriggeredAlarmId() //returns the currently triggered alarm id // returns dtINVALID_ALARM_ID if not invoked from within an alarm handler { if(isServicing) return servicedAlarmId; // new private data member used instead of local loop variable i in serviceAlarms(); else return dtINVALID_ALARM_ID; // valid ids only available when servicing a callback } // following functions are not Alarm ID specific. void TimeAlarmsClass::delay(unsigned long ms) { unsigned long start = millis(); while( millis() - start <= ms) serviceAlarms(); } void TimeAlarmsClass::waitForDigits( uint8_t Digits, dtUnits_t Units) { while(Digits != getDigitsNow(Units) ) { serviceAlarms(); } } void TimeAlarmsClass::waitForRollover( dtUnits_t Units) { while(getDigitsNow(Units) == 0 ) // if its just rolled over than wait for another rollover serviceAlarms(); waitForDigits(0, Units); } uint8_t TimeAlarmsClass::getDigitsNow( dtUnits_t Units) { time_t time = now(); if(Units == dtSecond) return numberOfSeconds(time); if(Units == dtMinute) return numberOfMinutes(time); if(Units == dtHour) return numberOfHours(time); if(Units == dtDay) return dayOfWeek(time); return 255; // This should never happen } //*********************************************************** //* Private Methods void TimeAlarmsClass::serviceAlarms() { if(! isServicing) { isServicing = true; for( servicedAlarmId = 0; servicedAlarmId < dtNBR_ALARMS; servicedAlarmId++) { if( Alarm[servicedAlarmId].Mode.isEnabled && (now() >= Alarm[servicedAlarmId].nextTrigger) ) { OnTick_t TickHandler = Alarm[servicedAlarmId].onTickHandler; if(Alarm[servicedAlarmId].Mode.isOneShot) free(servicedAlarmId); // free the ID if mode is OnShot else Alarm[servicedAlarmId].updateNextTrigger(); if( TickHandler != NULL) { (*TickHandler)(); // call the handler } } } isServicing = false; } } // returns the absolute time of the next scheduled alarm, or 0 if none time_t TimeAlarmsClass::getNextTrigger() { time_t nextTrigger = 0xffffffff; // the max time value for(uint8_t id = 0; id < dtNBR_ALARMS; id++) { if(isAllocated(id) ) { if(Alarm[id].nextTrigger < nextTrigger) nextTrigger = Alarm[id].nextTrigger; } } return nextTrigger == 0xffffffff ? 0 : nextTrigger; } // attempt to create an alarm and return true if successful AlarmID_t TimeAlarmsClass::create( time_t value, OnTick_t onTickHandler, uint8_t isOneShot, dtAlarmPeriod_t alarmType, uint8_t isEnabled) { if( ! (dtIsAlarm(alarmType) && now() < SECS_PER_YEAR)) // only create alarm ids if the time is at least Jan 1 1971 { for(uint8_t id = 0; id < dtNBR_ALARMS; id++) { if( Alarm[id].Mode.alarmType == dtNotAllocated ) { // here if there is an Alarm id that is not allocated Alarm[id].onTickHandler = onTickHandler; Alarm[id].Mode.isOneShot = isOneShot; Alarm[id].Mode.alarmType = alarmType; Alarm[id].value = value; isEnabled ? enable(id) : disable(id); return id; // alarm created ok } } } return dtINVALID_ALARM_ID; // no IDs available or time is invalid } // make one instance for the user to use TimeAlarmsClass Alarm = TimeAlarmsClass() ; \ No newline at end of file diff --git a/TimeAlarms/TimeAlarms.h b/TimeAlarms/TimeAlarms.h new file mode 100644 index 0000000..fd82b10 --- /dev/null +++ b/TimeAlarms/TimeAlarms.h @@ -0,0 +1,127 @@ +// TimeAlarms.h - Arduino Time alarms header for use with Time library + +#ifndef TimeAlarms_h +#define TimeAlarms_h + +#include + +#include "Time.h" + +#define dtNBR_ALARMS 6 // max is 255 + +#define USE_SPECIALIST_METHODS // define this for testing + +typedef enum { dtMillisecond, dtSecond, dtMinute, dtHour, dtDay } dtUnits_t; + +typedef struct { + uint8_t alarmType :4 ; // enumeration of daily/weekly (in future: biweekly/semimonthly/monthly/annual) + // note that the current API only supports daily or weekly alarm periods + uint8_t isEnabled :1 ; // the timer is only actioned if isEnabled is true + uint8_t isOneShot :1 ; // the timer will be de-allocated after trigger is processed + } + AlarmMode_t ; + +// new time based alarms should be added just before dtLastAlarmType +typedef enum {dtNotAllocated, dtTimer, dtExplicitAlarm, dtDailyAlarm, dtWeeklyAlarm, dtLastAlarmType } dtAlarmPeriod_t ; // in future: dtBiweekly, dtMonthly, dtAnnual + +// macro to return true if the given type is a time based alarm, false if timer or not allocated +#define dtIsAlarm(_type_) (_type_ >= dtExplicitAlarm && _type_ < dtLastAlarmType) + +typedef uint8_t AlarmID_t; +typedef AlarmID_t AlarmId; // Arduino friendly name + +#define dtINVALID_ALARM_ID 255 +#define dtINVALID_TIME 0L + +class AlarmClass; // forward reference +typedef void (*OnTick_t)(); // alarm callback function typedef + +// class defining an alarm instance, only used by dtAlarmsClass +class AlarmClass +{ +private: + +public: + AlarmClass(); + OnTick_t onTickHandler; + void updateNextTrigger(); + time_t value; + time_t nextTrigger; + AlarmMode_t Mode; +}; + +// class containing the collection of alarms +class TimeAlarmsClass +{ +private: + AlarmClass Alarm[dtNBR_ALARMS]; + void serviceAlarms(); + uint8_t isServicing; + uint8_t servicedAlarmId; // the alarm currently being serviced + AlarmID_t create( time_t value, OnTick_t onTickHandler, uint8_t isOneShot, dtAlarmPeriod_t alarmType, uint8_t isEnabled=true); + +public: + TimeAlarmsClass(); + // functions to create alarms and timers + + AlarmID_t triggerOnce(time_t value, OnTick_t onTickHandler); // trigger once at the given time_t + + AlarmID_t alarmRepeat(time_t value, OnTick_t onTickHandler); // trigger daily at given time of day + AlarmID_t alarmRepeat(const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with hms arguments + AlarmID_t alarmRepeat(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with day of week + + AlarmID_t alarmOnce(time_t value, OnTick_t onTickHandler); // trigger once at given time of day + AlarmID_t alarmOnce( const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with hms arguments + AlarmID_t alarmOnce(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with day of week + + AlarmID_t timerOnce(time_t value, OnTick_t onTickHandler); // trigger once after the given number of seconds + AlarmID_t timerOnce(const int H, const int M, const int S, OnTick_t onTickHandler); // As above with HMS arguments + + AlarmID_t timerRepeat(time_t value, OnTick_t onTickHandler); // trigger after the given number of seconds continuously + AlarmID_t timerRepeat(const int H, const int M, const int S, OnTick_t onTickHandler); // As above with HMS arguments + + void delay(unsigned long ms); + + // utility methods + uint8_t getDigitsNow( dtUnits_t Units); // returns the current digit value for the given time unit + void waitForDigits( uint8_t Digits, dtUnits_t Units); + void waitForRollover(dtUnits_t Units); + + // low level methods + void enable(AlarmID_t ID); // enable the alarm to trigger + void disable(AlarmID_t ID); // prevent the alarm from triggering + AlarmID_t getTriggeredAlarmId(); // returns the currently triggered alarm id + void write(AlarmID_t ID, time_t value); // write the value (and enable) the alarm with the given ID + time_t read(AlarmID_t ID); // return the value for the given timer + dtAlarmPeriod_t readType(AlarmID_t ID); // return the alarm type for the given alarm ID + +#ifndef USE_SPECIALIST_METHODS +private: // the following methods are for testing and are not documented as part of the standard library +#endif + void free(AlarmID_t ID); // free the id to allow its reuse + uint8_t count(); // returns the number of allocated timers + time_t getNextTrigger(); // returns the time of the next scheduled alarm + bool isAllocated(AlarmID_t ID); // returns true if this id is allocated + bool isAlarm(AlarmID_t ID); // returns true if id is for a time based alarm, false if its a timer or not allocated +}; + +extern TimeAlarmsClass Alarm; // make an instance for the user + +/*============================================================================== + * MACROS + *============================================================================*/ + +/* public */ +#define waitUntilThisSecond(_val_) waitForDigits( _val_, dtSecond) +#define waitUntilThisMinute(_val_) waitForDigits( _val_, dtMinute) +#define waitUntilThisHour(_val_) waitForDigits( _val_, dtHour) +#define waitUntilThisDay(_val_) waitForDigits( _val_, dtDay) +#define waitMinuteRollover() waitForRollover(dtSecond) +#define waitHourRollover() waitForRollover(dtMinute) +#define waitDayRollover() waitForRollover(dtHour) + +#define AlarmHMS(_hr_, _min_, _sec_) (_hr_ * SECS_PER_HOUR + _min_ * SECS_PER_MIN + _sec_) + + +#endif /* TimeAlarms_h */ + diff --git a/TimeAlarms/keywords.txt b/TimeAlarms/keywords.txt new file mode 100644 index 0000000..1843a88 --- /dev/null +++ b/TimeAlarms/keywords.txt @@ -0,0 +1,25 @@ +####################################### +# Syntax Coloring Map For TimeAlarms +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +alarmRepeat KEYWORD2 +alarmOnce KEYWORD2 +timerRepeat KEYWORD2 +timerOnce KEYWORD2 +delay KEYWORD2 +####################################### +# Instances (KEYWORD2) +####################################### +Alarm KEYWORD2 +####################################### +# Constants (LITERAL1) +####################################### +dtINVALID_ALARM_ID LITERAL1 +dtINVALID_TIME LITERAL1 \ No newline at end of file diff --git a/TimeAlarms/readme.txt b/TimeAlarms/readme.txt new file mode 100644 index 0000000..e158c8d --- /dev/null +++ b/TimeAlarms/readme.txt @@ -0,0 +1,220 @@ +Alarms + +The Alarm library is a companion to the Time library that makes it easy to +perform tasks at specific times or after specific intervals. + +Tasks scheduled at a particular time of day are called Alarms, +tasks scheduled after an interval of time has elapsed are called Timers. +These tasks can be created to continuously repeat or to occur once only. + +Here is how you create an alarm to trigger a task repeatedly at a particular time of day: + Alarm.alarmRepeat(8,30,0, MorningAlarm); +This would call the function MorningAlarm() at 8:30 am every day. + +If you want the alarm to trigger only once you can use the alarmOnce method: + Alarm.alarmOnce(8,30,0, MorningAlarm); +This calls a MorningAlarm() function in a sketch once only (when the time is next 8:30am) + +Alarms can be specified to trigger a task repeatedly at a particular day of week and time of day: + Alarm.alarmRepeat(dowMonday, 9,15,0, MondayMorningAlarm); +This would call the function WeeklyAlarm() at 9:15am every Monday. + +If you want the alarm to trigger once only on a particular day and time you can do this: + Alarm.alarmOnce(dowMonday, 9,15,0, MondayMorningAlarm); +This would call the function MondayMorning() Alarm on the next Monday at 9:15am. + +Timers trigger tasks that occur after a specified interval of time has passed. +The timer interval can be specified in seconds, or in hour, minutes and seconds. + Alarm.timerRepeat(15, Repeats); // timer task every 15 seconds +This calls the Repeats() function in your sketch every 15 seconds. + +If you want a timer to trigger once only, you can use the timerOnce method: + Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds +This calls the onceOnly() function in a sketch 10 seconds after the timer is created. + +If you want to trigger once at a specified date and time you can use the trigger Once() method: + Alarm. triggerOnce(time_t value, explicitAlarm); // value specifies a date and time +(See the makeTime() method in the Time library to convert dates and times into time_t) + +Your sketch should call the Alarm.delay() function instead of the Arduino delay() function when +using the Alarms library. The timeliness of triggers depends on sketch delays using this function. + Alarm.delay( period); // Similar to Arduino delay - pauses the program for the period (in milliseconds). + + + +Here is an example sketch: + +This sketch triggers daily alarms at 8:30 am and 17:45 pm. +A Timer is triggered every 15 seconds, another timer triggers once only after 10 seconds. +A weekly alarm is triggered every Sunday at 8:30:30 + +#include +#include + +void setup() +{ + Serial.begin(9600); + setTime(8,29,0,1,1,11); // set time to Saturday 8:29:00am Jan 1 2011 + // create the alarms + Alarm.alarmRepeat(8,30,0, MorningAlarm); // 8:30am every day + Alarm.alarmRepeat(17,45,0,EveningAlarm); // 5:45pm every day + Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm); // 8:30:30 every Saturday + + + Alarm.timerRepeat(15, Repeats); // timer for every 15 seconds + Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds +} + +void loop(){ + digitalClockDisplay(); + Alarm.delay(1000); // wait one second between clock display +} + +// functions to be called when an alarm triggers: +void MorningAlarm(){ + Serial.println("Alarm: - turn lights off"); +} + +void EveningAlarm(){ + Serial.println("Alarm: - turn lights on"); +} + +void WeeklyAlarm(){ + Serial.println("Alarm: - its Monday Morning"); +} + +void ExplicitAlarm(){ + Serial.println("Alarm: - this triggers only at the given date and time"); +} + +void Repeats(){ + Serial.println("15 second timer"); +} + +void OnceOnly(){ + Serial.println("This timer only triggers once"); +} + +void digitalClockDisplay() +{ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.println(); +} + +void printDigits(int digits) +{ + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} +Note that the loop code calls Alarm.delay(1000) - Alarm.delay must be used +instead of the usual arduino delay function because the alarms are serviced in the Alarm.delay method. +Failing to regularly call Alarm.delay will result in the alarms not being triggered +so always use Alarm.delay instead of delay in sketches that use the Alarms library. + +Functional reference: + +// functions to create alarms and timers + +Alarm.triggerOnce(value, AlarmFunction); + Description: Call user provided AlarmFunction once at the date and time of the given value + See the Ttime library for more on time_t values + +Alarm.alarmRepeat(Hour, Minute, Second, AlarmFunction); + Description: Calls user provided AlarmFunction every day at the given Hour, Minute and Second. + +Alarm.alarmRepeat(value, AlarmFunction); + Description: Calls user provided AlarmFunction every day at the time indicated by the given value + +Alarm.alarmRepeat(DayOfWeek, Hour, Minute, Second, AlarmFunction); + Description: Calls user provided AlarmFunction every week on the given DayOfWeek, Hour, Minute and Second. + +Alarm.alarmOnce(Hour, Minute, Second, AlarmFunction); + Description: Calls user provided AlarmFunction once when the Arduino time next reaches the given Hour, Minute and Second. + +Alarm.alarmOnce(value, AlarmFunction); + Description: Calls user provided AlarmFunction once at the next time indicated by the given value + +Alarm.alarmOnce(DayOfWeek, Hour, Minute, Second, AlarmFunction); + Description: Calls user provided AlarmFunction once only on the next DayOfWeek, Hour, Minute and Second. + +Alarm.timerRepeat(Period, TimerFunction); + Description: Continuously calls user provided TimerFunction after the given period in seconds has elapsed. + +Alarm.timerRepeat(Hour, Minute, Second, TimerFunction); + Description: As timerRepeat above, but period is the number of seconds in the given Hour, Minute and Second parameters + +Alarm.timerOnce(Period, TimerFunction); + Description: Calls user provided TimerFunction once only after the given period in seconds has elapsed. + +Alarm.timerOnce(Hour, Minute, Second, TimerFunction); + Description: As timerOnce above, but period is the number of seconds in the given Hour, Minute and Second parameters + +Alarm.delay( period) + Description: Similar to Arduino delay - pauses the program for the period (in miliseconds) specified. + Call this function rather than the Arduino delay function when using the Alarms library. + The timeliness of the triggers depends on sketch delays using this function. + +Low level functions not usually required for typical applications: + disable( ID); - prevent the alarm associated with the given ID from triggering + enable(ID); - enable the alarm + write(ID, value); - write the value (and enable) the alarm for the given ID + read(ID); - return the value for the given ID + readType(ID); - return the alarm type for the given alarm ID + getTriggeredAlarmId(); - returns the currently triggered alarm id, only valid in an alarm callback + +FAQ + +Q: What hardware and software is needed to use this library? +A: This library requires the Time library. No internal or external hardware is used by the Alarm library. + +Q: Why must I use Alarm.delay() instead of delay()? +A: Task scheduling is handled in the Alarm.delay function. +Tasks are monitored and triggered from within the Alarm.delay call so Alarm.delay should be called +whenever a delay is required in your sketch. +If your sketch waits on an external event (for example, a sensor change), +make sure you repeatedly call Alarm.delay while checking the sensor. +You can call Alarm.delay(0) if you need to service the scheduler without a delay. + +Q: Are there any restrictions on the code in a task handler function? +A: No. The scheduler does not use interrupts so your task handling function is no +different from other functions you create in your sketch. + +Q: What are the shortest and longest intervals that can be scheduled? +A: Time intervals can range from 1 second to years. +(If you need timer intervals shorter than 1 second then the TimedAction library +by Alexander Brevig may be more suitable, see: http://www.arduino.cc/playground/Code/TimedAction) + +Q: How are scheduled tasks affected if the system time is changed? +A: Tasks are scheduled for specific times designated by the system clock. +If the system time is reset to a later time (for example one hour ahead) then all +alarms and timers will occur one hour later. +If the system time is set backwards (for example one hour back) then the alarms and timers will occur an hour earlier. +If the time is reset before the time a task was scheduled, then the task will be triggered on the next service (the next call to Alarm.delay). +This is the expected behaviour for Alarms – tasks scheduled for a specific time of day will trigger at that time, but the affect on timers may not be intuitive. If a timer is scheduled to trigger in 5 minutes time and the clock is set ahead by one hour, that timer will not trigger until one hour and 5 minutes has elapsed. + +Q: What is the valid range of times supported by these libraries? +A: The time library is intended to handle times from Jan 1 1970 through Jan 19 2038. + The Alarms library expects dates to be on or after Jan1 1971 so clocks should no be set earlier than this if using Alarms. +(The functions to create alarms will return an error if an earlier date is given). + +Q: How many alarms can be created? +A: Up to six alarms can be scheduled. +The number of alarms can be changed in the TimeAlarms header file (set by the constant dtNBR_ALARMS, +note that the RAM used equals dtNBR_ALARMS * 11) + +onceOnly Alarms and Timers are freed when they are triggered so another onceOnly alarm can be set to trigger again. +There is no limit to the number of times a onceOnly alarm can be reset. + +The following fragment gives one example of how a timerOnce task can be rescheduled: +Alarm.timerOnce(random(10), randomTimer); // trigger after random number of seconds + +void randomTimer(){ + int period = random(2,10); // get a new random period + Alarm.timerOnce(period, randomTimer); // trigger for another random period +} + -- cgit v1.2.3