Windows Arduino 1.0.X does not like to import zip files. Unzipped to make installation easier.

This commit is contained in:
foley@ru.is
2014-01-15 17:18:08 +00:00
parent 0ff28de55a
commit e3daa0cee0
24 changed files with 2563 additions and 0 deletions

View File

@@ -0,0 +1,357 @@
/*
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 <string.h> // for memset
}
#if ARDUINO > 22
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#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() ;

View File

@@ -0,0 +1,127 @@
// TimeAlarms.h - Arduino Time alarms header for use with Time library
#ifndef TimeAlarms_h
#define TimeAlarms_h
#include <inttypes.h>
#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 */

View File

@@ -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 <Time.h>
#include <TimeAlarms.h>
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);
}

View File

@@ -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

View File

@@ -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 <Time.h>
#include <TimeAlarms.h>
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 <20> 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
}