@@ -1,67 +1,25 @@
#include <Wire.h>
#include <pitches.h>

// Constant variables
const int speaker = 2;

// Variables

// NOTES
int C[] = { NOTE_C1, NOTE_C2, NOTE_C3, NOTE_C4, NOTE_C5, NOTE_C6, NOTE_C7 };
int D[] = { NOTE_D1, NOTE_D2, NOTE_D3, NOTE_D4, NOTE_D5, NOTE_D6, NOTE_D7 };
int E[] = { NOTE_E1, NOTE_E2, NOTE_E3, NOTE_E4, NOTE_E5, NOTE_E6, NOTE_E7 };
int F[] = { NOTE_F1, NOTE_F2, NOTE_F3, NOTE_F4, NOTE_F5, NOTE_F6, NOTE_F7 };
int G[] = { NOTE_G1, NOTE_G2, NOTE_G3, NOTE_G4, NOTE_G5, NOTE_G6, NOTE_G7 };
int A[] = { NOTE_A1, NOTE_A2, NOTE_A3, NOTE_A4, NOTE_A5, NOTE_A6, NOTE_A7 };
int B[] = { NOTE_B1, NOTE_B2, NOTE_B3, NOTE_B4, NOTE_B5, NOTE_B6, NOTE_B7 };

int CS[] = { NOTE_CS1, NOTE_CS2, NOTE_CS3, NOTE_CS4, NOTE_CS5, NOTE_CS6, NOTE_CS7 };
int DS[] = { NOTE_DS1, NOTE_DS2, NOTE_DS3, NOTE_DS4, NOTE_DS5, NOTE_DS6, NOTE_DS7 };
int FS[] = { NOTE_FS1, NOTE_FS2, NOTE_FS3, NOTE_FS4, NOTE_FS5, NOTE_FS6, NOTE_FS7 };
int GS[] = { NOTE_GS1, NOTE_GS2, NOTE_GS3, NOTE_GS4, NOTE_GS5, NOTE_GS6, NOTE_GS7 };
int AS[] = { NOTE_AS1, NOTE_AS2, NOTE_AS3, NOTE_AS4, NOTE_AS5, NOTE_AS6, NOTE_AS7 };
const int buzzer = 4;

void setup() {
pinMode(speaker, OUTPUT);
Serial.begin(9600);
Wire.begin(8);
Wire.onReceive(receiveEvent);
pinMode(buzzer, OUTPUT);
noTone(buzzer);
}

void loop() {
for(int i = 0; i < 2; i++) {
playNote(AS[3], 4);
playNote(F[4], 4);
playNote(DS[4], 4);
playNote(AS[3], 4);
playNote(D[4], 3);
playNote(D[4], 3);
playNote(DS[4], 2);

playNote(AS[3], 4);
playNote(DS[4], 4);
playNote(AS[3], 4);
playNote(D[4], 3);
playNote(D[4], 3);
playNote(DS[4], 4);

playNote(AS[3], 4);
playNote(F[4], 4);
playNote(DS[4], 4);
playNote(AS[3], 4);
playNote(D[4], 3);
playNote(D[4], 3);
playNote(DS[4], 2);

playNote(AS[3], 4);
playNote(DS[4], 4);
playNote(G[4], 4);
playNote(F[4], 3);
playNote(DS[4], 3);
playNote(F[4], 4);
}

delay(1000);
delay(150);
}

void playNote(int note, float length) {
tone(speaker, note, 1000/ length);
delay(1000 / length * 1.3);
noTone(speaker);
}
void receiveEvent(int howMany) {
unsigned int note = Wire.read();
Serial.println(note);
noTone(buzzer);
if(note != 0) tone(buzzer, note);
}

Large diffs are not rendered by default.

@@ -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() ;

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

@@ -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);
}

@@ -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
@@ -0,0 +1,16 @@
{
"name": "TimeAlarms",
"frameworks": "Arduino",
"keywords": "Time, alarm, schedule, date, hour, minute, second, day, week, month, year",
"description": "Schedule alarms to occur at specific times",
"url": "http://playground.arduino.cc/Code/Time",
"authors":
{
"name": "Michael Margolis"
},
"repository":
{
"type": "git",
"url": "https://github.com/PaulStoffregen/TimeAlarms"
}
}
@@ -0,0 +1,10 @@
name=TimeAlarms
version=1.4
author=Michael Margolis
maintainer=Paul Stoffregen
sentence=Perform tasks at specific times or after specific intervals.
paragraph=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.
category=Timing
url=http://playground.arduino.cc/code/time
architectures=*

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

@@ -0,0 +1,33 @@
#TimerOne Library#

Paul Stoffregen's modified TimerOne. This version provides 2 main benefits:

1: Optimized inline functions - much faster for the most common usage
2: Support for more boards

http://www.pjrc.com/teensy/td_libs_TimerOne.html

https://github.com/PaulStoffregen/TimerOne

Original code

http://playground.arduino.cc/Code/Timer1

Open Source License

TimerOne is free software. You can redistribute it and/or modify it under
the terms of Creative Commons Attribution 3.0 United States License.
To view a copy of this license, visit

http://creativecommons.org/licenses/by/3.0/us/

Paul Stoffregen forked this version from an early copy of TimerOne/TimerThree
which was licensed "Creative Commons Attribution 3.0" and has maintained
the original "CC BY 3.0 US" license terms.

Other, separately developed updates to TimerOne have been released by other
authors under the GNU GPLv2 license. Multiple copies of this library, bearing
the same name but distributed under different license terms, is unfortunately
confusing. This copy, with nearly all the code redesigned as inline functions,
is provided under the "CC BY 3.0 US" license terms.

@@ -0,0 +1,44 @@
/*
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
* Original code by Jesse Tane for http://labs.ideo.com August 2008
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
* Modified Oct 2009 by Dan Clemens to work with timer1 of the ATMega1280 or Arduino Mega
* Modified April 2012 by Paul Stoffregen
* Modified again, June 2014 by Paul Stoffregen
*
* This is free software. You can redistribute it and/or modify it under
* the terms of Creative Commons Attribution 3.0 United States License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
* or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*
*/

#include "TimerOne.h"

TimerOne Timer1; // preinstatiate

unsigned short TimerOne::pwmPeriod = 0;
unsigned char TimerOne::clockSelectBits = 0;
void (*TimerOne::isrCallback)() = NULL;

// interrupt service routine that wraps a user defined function supplied by attachInterrupt
#if defined(__AVR__)
ISR(TIMER1_OVF_vect)
{
Timer1.isrCallback();
}

#elif defined(__arm__) && defined(CORE_TEENSY)
void ftm1_isr(void)
{
uint32_t sc = FTM1_SC;
#ifdef KINETISL
if (sc & 0x80) FTM1_SC = sc;
#else
if (sc & 0x80) FTM1_SC = sc & 0x7F;
#endif
Timer1.isrCallback();
}

#endif
@@ -0,0 +1,304 @@
/*
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
* Original code by Jesse Tane for http://labs.ideo.com August 2008
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
* Modified April 2012 by Paul Stoffregen - portable to other AVR chips, use inline functions
* Modified again, June 2014 by Paul Stoffregen - support Teensy 3.x & even more AVR chips
*
*
* This is free software. You can redistribute it and/or modify it under
* the terms of Creative Commons Attribution 3.0 United States License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
* or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*
*/

#ifndef TimerOne_h_
#define TimerOne_h_

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "config/known_16bit_timers.h"

#define TIMER1_RESOLUTION 65536UL // Timer1 is 16 bit


// Placing nearly all the code in this .h file allows the functions to be
// inlined by the compiler. In the very common case with constant values
// the compiler will perform all calculations and simply write constants
// to the hardware registers (for example, setPeriod).


class TimerOne
{


#if defined(__AVR__)
public:
//****************************
// Configuration
//****************************
void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
TCCR1B = _BV(WGM13); // set mode as phase and frequency correct pwm, stop the timer
TCCR1A = 0; // clear control register A
setPeriod(microseconds);
}
void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
const unsigned long cycles = (F_CPU / 2000000) * microseconds;
if (cycles < TIMER1_RESOLUTION) {
clockSelectBits = _BV(CS10);
pwmPeriod = cycles;
} else
if (cycles < TIMER1_RESOLUTION * 8) {
clockSelectBits = _BV(CS11);
pwmPeriod = cycles / 8;
} else
if (cycles < TIMER1_RESOLUTION * 64) {
clockSelectBits = _BV(CS11) | _BV(CS10);
pwmPeriod = cycles / 64;
} else
if (cycles < TIMER1_RESOLUTION * 256) {
clockSelectBits = _BV(CS12);
pwmPeriod = cycles / 256;
} else
if (cycles < TIMER1_RESOLUTION * 1024) {
clockSelectBits = _BV(CS12) | _BV(CS10);
pwmPeriod = cycles / 1024;
} else {
clockSelectBits = _BV(CS12) | _BV(CS10);
pwmPeriod = TIMER1_RESOLUTION - 1;
}
ICR1 = pwmPeriod;
TCCR1B = _BV(WGM13) | clockSelectBits;
}

//****************************
// Run Control
//****************************
void start() __attribute__((always_inline)) {
TCCR1B = 0;
TCNT1 = 0; // TODO: does this cause an undesired interrupt?
resume();
}
void stop() __attribute__((always_inline)) {
TCCR1B = _BV(WGM13);
}
void restart() __attribute__((always_inline)) {
start();
}
void resume() __attribute__((always_inline)) {
TCCR1B = _BV(WGM13) | clockSelectBits;
}

//****************************
// PWM outputs
//****************************
void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
unsigned long dutyCycle = pwmPeriod;
dutyCycle *= duty;
dutyCycle >>= 10;
if (pin == TIMER1_A_PIN) OCR1A = dutyCycle;
#ifdef TIMER1_B_PIN
else if (pin == TIMER1_B_PIN) OCR1B = dutyCycle;
#endif
#ifdef TIMER1_C_PIN
else if (pin == TIMER1_C_PIN) OCR1C = dutyCycle;
#endif
}
void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
if (pin == TIMER1_A_PIN) { pinMode(TIMER1_A_PIN, OUTPUT); TCCR1A |= _BV(COM1A1); }
#ifdef TIMER1_B_PIN
else if (pin == TIMER1_B_PIN) { pinMode(TIMER1_B_PIN, OUTPUT); TCCR1A |= _BV(COM1B1); }
#endif
#ifdef TIMER1_C_PIN
else if (pin == TIMER1_C_PIN) { pinMode(TIMER1_C_PIN, OUTPUT); TCCR1A |= _BV(COM1C1); }
#endif
setPwmDuty(pin, duty);
TCCR1B = _BV(WGM13) | clockSelectBits;
}
void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
if (microseconds > 0) setPeriod(microseconds);
pwm(pin, duty);
}
void disablePwm(char pin) __attribute__((always_inline)) {
if (pin == TIMER1_A_PIN) TCCR1A &= ~_BV(COM1A1);
#ifdef TIMER1_B_PIN
else if (pin == TIMER1_B_PIN) TCCR1A &= ~_BV(COM1B1);
#endif
#ifdef TIMER1_C_PIN
else if (pin == TIMER1_C_PIN) TCCR1A &= ~_BV(COM1C1);
#endif
}

//****************************
// Interrupt Function
//****************************
void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
isrCallback = isr;
TIMSK1 = _BV(TOIE1);
}
void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
if(microseconds > 0) setPeriod(microseconds);
attachInterrupt(isr);
}
void detachInterrupt() __attribute__((always_inline)) {
TIMSK1 = 0;
}
static void (*isrCallback)();

private:
// properties
static unsigned short pwmPeriod;
static unsigned char clockSelectBits;






#elif defined(__arm__) && defined(CORE_TEENSY)

#if defined(KINETISK)
#define F_TIMER F_BUS
#elif defined(KINETISL)
#define F_TIMER (F_PLL/2)
#endif

public:
//****************************
// Configuration
//****************************
void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
setPeriod(microseconds);
}
void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
const unsigned long cycles = (F_TIMER / 2000000) * microseconds;
if (cycles < TIMER1_RESOLUTION) {
clockSelectBits = 0;
pwmPeriod = cycles;
} else
if (cycles < TIMER1_RESOLUTION * 2) {
clockSelectBits = 1;
pwmPeriod = cycles >> 1;
} else
if (cycles < TIMER1_RESOLUTION * 4) {
clockSelectBits = 2;
pwmPeriod = cycles >> 2;
} else
if (cycles < TIMER1_RESOLUTION * 8) {
clockSelectBits = 3;
pwmPeriod = cycles >> 3;
} else
if (cycles < TIMER1_RESOLUTION * 16) {
clockSelectBits = 4;
pwmPeriod = cycles >> 4;
} else
if (cycles < TIMER1_RESOLUTION * 32) {
clockSelectBits = 5;
pwmPeriod = cycles >> 5;
} else
if (cycles < TIMER1_RESOLUTION * 64) {
clockSelectBits = 6;
pwmPeriod = cycles >> 6;
} else
if (cycles < TIMER1_RESOLUTION * 128) {
clockSelectBits = 7;
pwmPeriod = cycles >> 7;
} else {
clockSelectBits = 7;
pwmPeriod = TIMER1_RESOLUTION - 1;
}
uint32_t sc = FTM1_SC;
FTM1_SC = 0;
FTM1_MOD = pwmPeriod;
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);
}

//****************************
// Run Control
//****************************
void start() __attribute__((always_inline)) {
stop();
FTM1_CNT = 0;
resume();
}
void stop() __attribute__((always_inline)) {
FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));
}
void restart() __attribute__((always_inline)) {
start();
}
void resume() __attribute__((always_inline)) {
FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);
}

//****************************
// PWM outputs
//****************************
void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
unsigned long dutyCycle = pwmPeriod;
dutyCycle *= duty;
dutyCycle >>= 10;
if (pin == TIMER1_A_PIN) {
FTM1_C0V = dutyCycle;
} else if (pin == TIMER1_B_PIN) {
FTM1_C1V = dutyCycle;
}
}
void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
setPwmDuty(pin, duty);
if (pin == TIMER1_A_PIN) {
*portConfigRegister(TIMER1_A_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
} else if (pin == TIMER1_B_PIN) {
*portConfigRegister(TIMER1_B_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
}
}
void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
if (microseconds > 0) setPeriod(microseconds);
pwm(pin, duty);
}
void disablePwm(char pin) __attribute__((always_inline)) {
if (pin == TIMER1_A_PIN) {
*portConfigRegister(TIMER1_A_PIN) = 0;
} else if (pin == TIMER1_B_PIN) {
*portConfigRegister(TIMER1_B_PIN) = 0;
}
}

//****************************
// Interrupt Function
//****************************
void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
isrCallback = isr;
FTM1_SC |= FTM_SC_TOIE;
NVIC_ENABLE_IRQ(IRQ_FTM1);
}
void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
if(microseconds > 0) setPeriod(microseconds);
attachInterrupt(isr);
}
void detachInterrupt() __attribute__((always_inline)) {
FTM1_SC &= ~FTM_SC_TOIE;
NVIC_DISABLE_IRQ(IRQ_FTM1);
}
static void (*isrCallback)();

private:
// properties
static unsigned short pwmPeriod;
static unsigned char clockSelectBits;

#undef F_TIMER

#endif
};

extern TimerOne Timer1;

#endif

@@ -0,0 +1,143 @@
#ifndef known_16bit_timers_header_
#define known_16bit_timers_header_

// Wiring-S
//
#if defined(__AVR_ATmega644P__) && defined(WIRING)
#define TIMER1_A_PIN 5
#define TIMER1_B_PIN 4
#define TIMER1_ICP_PIN 6

// Teensy 2.0
//
#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
#define TIMER1_A_PIN 14
#define TIMER1_B_PIN 15
#define TIMER1_C_PIN 4
#define TIMER1_ICP_PIN 22
#define TIMER1_CLK_PIN 11
#define TIMER3_A_PIN 9
#define TIMER3_ICP_PIN 10

// Teensy++ 2.0
#elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY)
#define TIMER1_A_PIN 25
#define TIMER1_B_PIN 26
#define TIMER1_C_PIN 27
#define TIMER1_ICP_PIN 4
#define TIMER1_CLK_PIN 6
#define TIMER3_A_PIN 16
#define TIMER3_B_PIN 15
#define TIMER3_C_PIN 14
#define TIMER3_ICP_PIN 17
#define TIMER3_CLK_PIN 13

// Teensy 3.0
//
#elif defined(__MK20DX128__)
#define TIMER1_A_PIN 3
#define TIMER1_B_PIN 4
#define TIMER1_ICP_PIN 4

// Teensy 3.1
//
#elif defined(__MK20DX256__)
#define TIMER1_A_PIN 3
#define TIMER1_B_PIN 4
#define TIMER1_ICP_PIN 4
#define TIMER3_A_PIN 32
#define TIMER3_B_PIN 25
#define TIMER3_ICP_PIN 32

// Teensy-LC
//
#elif defined(__MKL26Z64__)
#define TIMER1_A_PIN 16
#define TIMER1_B_PIN 17
#define TIMER1_ICP_PIN 17
#define TIMER3_A_PIN 3
#define TIMER3_B_PIN 4
#define TIMER3_ICP_PIN 4

// Arduino Mega
//
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TIMER1_A_PIN 11
#define TIMER1_B_PIN 12
#define TIMER1_C_PIN 13
#define TIMER3_A_PIN 5
#define TIMER3_B_PIN 2
#define TIMER3_C_PIN 3
#define TIMER4_A_PIN 6
#define TIMER4_B_PIN 7
#define TIMER4_C_PIN 8
#define TIMER4_ICP_PIN 49
#define TIMER5_A_PIN 46
#define TIMER5_B_PIN 45
#define TIMER5_C_PIN 44
#define TIMER3_ICP_PIN 48
#define TIMER3_CLK_PIN 47

// Arduino Leonardo, Yun, etc
//
#elif defined(__AVR_ATmega32U4__)
#define TIMER1_A_PIN 9
#define TIMER1_B_PIN 10
#define TIMER1_C_PIN 11
#define TIMER1_ICP_PIN 4
#define TIMER1_CLK_PIN 12
#define TIMER3_A_PIN 5
#define TIMER3_ICP_PIN 13

// Uno, Duemilanove, LilyPad, etc
//
#elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__)
#define TIMER1_A_PIN 9
#define TIMER1_B_PIN 10
#define TIMER1_ICP_PIN 8
#define TIMER1_CLK_PIN 5

// Sanguino
//
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#define TIMER1_A_PIN 13
#define TIMER1_B_PIN 12
#define TIMER1_ICP_PIN 14
#define TIMER1_CLK_PIN 1

// Wildfire - Wicked Devices
//
#elif defined(__AVR_ATmega1284P__) && defined(WILDFIRE_VERSION) && WILDFIRE_VERSION >= 3
#define TIMER1_A_PIN 5 // PD5
#define TIMER1_B_PIN 8 // PD4
#define TIMER1_ICP_PIN 6 // PD6
#define TIMER1_CLK_PIN 23 // PB1
#define TIMER3_A_PIN 12 // PB6
#define TIMER3_B_PIN 13 // PB7
#define TIMER3_ICP_PIN 9 // PB5
#define TIMER3_CLK_PIN 0 // PD0
#elif defined(__AVR_ATmega1284P__) && defined(WILDFIRE_VERSION) && WILDFIRE_VERSION < 3
#define TIMER1_A_PIN 5 // PD5
#define TIMER1_B_PIN 4 // PD4
#define TIMER1_ICP_PIN 6 // PD6
#define TIMER1_CLK_PIN 15 // PB1
#define TIMER3_A_PIN 12 // PB6
#define TIMER3_B_PIN 13 // PB7
#define TIMER3_ICP_PIN 11 // PB5
#define TIMER3_CLK_PIN 0 // PD0

// Mighty-1284 - Maniacbug
//
#elif defined(__AVR_ATmega1284P__)
#define TIMER1_A_PIN 12 // PD5
#define TIMER1_B_PIN 13 // PD4
#define TIMER1_ICP_PIN 14 // PD6
#define TIMER1_CLK_PIN 1 // PB1
#define TIMER3_A_PIN 6 // PB6
#define TIMER3_B_PIN 7 // PB7
#define TIMER3_ICP_PIN 5 // PB5
#define TIMER3_CLK_PIN 8 // PD0

#endif

#endif
@@ -0,0 +1,37 @@
#include <TimerOne.h>

// This example creates a PWM signal with 25 kHz carrier.
//
// Arduino's analogWrite() gives you PWM output, but no control over the
// carrier frequency. The default frequency is low, typically 490 or
// 3920 Hz. Sometimes you may need a faster carrier frequency.
//
// The specification for 4-wire PWM fans recommends a 25 kHz frequency
// and allows 21 to 28 kHz. The default from analogWrite() might work
// with some fans, but to follow the specification we need 25 kHz.
//
// http://www.formfactors.org/developer/specs/REV1_2_Public.pdf
//
// Connect the PWM pin to the fan's control wire (usually blue). The
// board's ground must be connected to the fan's ground, and the fan
// needs +12 volt power from the computer or a separate power supply.

const int fanPin = 4;

void setup(void)
{
Timer1.initialize(40); // 40 us = 25 kHz
Serial.begin(9600);
}

void loop(void)
{
// slowly increase the PWM fan speed
//
for (float dutyCycle = 30.0; dutyCycle < 100.0; dutyCycle++) {
Serial.print("PWM Fan, Duty Cycle = ");
Serial.println(dutyCycle);
Timer1.pwm(fanPin, (dutyCycle / 100) * 1023);
delay(500);
}
}
@@ -0,0 +1,54 @@
#include <TimerOne.h>

// This example uses the timer interrupt to blink an LED
// and also demonstrates how to share a variable between
// the interrupt and the main program.


const int led = LED_BUILTIN; // the pin with a LED

void setup(void)
{
pinMode(led, OUTPUT);
Timer1.initialize(150000);
Timer1.attachInterrupt(blinkLED); // blinkLED to run every 0.15 seconds
Serial.begin(9600);
}


// The interrupt will blink the LED, and keep
// track of how many times it has blinked.
int ledState = LOW;
volatile unsigned long blinkCount = 0; // use volatile for shared variables

void blinkLED(void)
{
if (ledState == LOW) {
ledState = HIGH;
blinkCount = blinkCount + 1; // increase when LED turns on
} else {
ledState = LOW;
}
digitalWrite(led, ledState);
}


// The main program will print the blink count
// to the Arduino Serial Monitor
void loop(void)
{
unsigned long blinkCopy; // holds a copy of the blinkCount

// to read a variable which the interrupt code writes, we
// must temporarily disable interrupts, to be sure it will
// not change while we are reading. To minimize the time
// with interrupts off, just quickly make a copy, and then
// use the copy while allowing the interrupt to keep working.
noInterrupts();
blinkCopy = blinkCount;
interrupts();

Serial.print("blinkCount = ");
Serial.println(blinkCopy);
delay(100);
}
@@ -0,0 +1,14 @@
Timer1 KEYWORD2
TimerOne KEYWORD1
initialize KEYWORD2
start KEYWORD2
stop KEYWORD2
restart KEYWORD2
resume KEYWORD2
pwm KEYWORD2
disablePwm KEYWORD2
attachInterrupt KEYWORD2
detachInterrupt KEYWORD2
setPeriod KEYWORD2
setPwmDuty KEYWORD2
isrCallback KEYWORD2
@@ -0,0 +1,16 @@
{
"name": "TimerOne",
"keywords": "timer",
"description": "Allow to use the built-in 16 bit Timer1",
"repository":
{
"type": "git",
"url": "https://github.com/PaulStoffregen/TimerOne.git"
},
"frameworks": "arduino",
"platforms":
[
"atmelavr",
"teensy"
]
}
@@ -0,0 +1,10 @@
name=TimerOne
version=1.1
author=Jesse Tane, Jérôme Despatis, Michael Polli, Dan Clemens, Paul Stoffregen
maintainer=Paul Stoffregen
sentence=Use hardware Timer1 for finer PWM control and/or running an periodic interrupt function
paragraph=
category=Timing
url=http://playground.arduino.cc/Code/Timer1
architectures=avr

@@ -0,0 +1,33 @@
#TimerThree Library#

Paul Stoffregen's modified TimerThree. This version provides 2 main benefits:

1: Optimized inline functions - much faster for the most common usage
2: Support for more boards

http://www.pjrc.com/teensy/td_libs_TimerOne.html

https://github.com/PaulStoffregen/TimerThree

Original code

http://playground.arduino.cc/Code/Timer1

Open Source License

TimerThree is free software. You can redistribute it and/or modify it under
the terms of Creative Commons Attribution 3.0 United States License.
To view a copy of this license, visit

http://creativecommons.org/licenses/by/3.0/us/

Paul Stoffregen forked this version from an early copy of TimerOne/TimerThree
which was licensed "Creative Commons Attribution 3.0" and has maintained
the original "CC BY 3.0 US" license terms.

Other, separately developed updates to TimerOne have been released by other
authors under the GNU GPLv2 license. Multiple copies of this library, bearing
the same name but distributed under different license terms, is unfortunately
confusing. This copy, with nearly all the code redesigned as inline functions,
is provided under the "CC BY 3.0 US" license terms.

@@ -0,0 +1,45 @@
/*
* Interrupt and PWM utilities for 16 bit Timer3 on ATmega168/328
* Original code by Jesse Tane for http://labs.ideo.com August 2008
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
* Modified Oct 2009 by Dan Clemens to work with timer3 of the ATMega1280 or Arduino Mega
* Modified April 2012 by Paul Stoffregen
* Modified again, June 2014 by Paul Stoffregen
*
* This is free software. You can redistribute it and/or modify it under
* the terms of Creative Commons Attribution 3.0 United States License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
* or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*
*/

#include "TimerThree.h"

TimerThree Timer3; // preinstatiate

unsigned short TimerThree::pwmPeriod = 0;
unsigned char TimerThree::clockSelectBits = 0;
void (*TimerThree::isrCallback)() = NULL;

// interrupt service routine that wraps a user defined function supplied by attachInterrupt
#if defined(__AVR__)
ISR(TIMER3_OVF_vect)
{
Timer3.isrCallback();
}

#elif defined(__arm__) && defined(CORE_TEENSY)
void ftm2_isr(void)
{
uint32_t sc = FTM2_SC;
#ifdef KINETISL
if (sc & 0x80) FTM2_SC = sc;
#else
if (sc & 0x80) FTM2_SC = sc & 0x7F;
#endif
Timer3.isrCallback();
}

#endif

@@ -0,0 +1,301 @@
/*
* Interrupt and PWM utilities for 16 bit Timer3 on ATmega168/328
* Original code by Jesse Tane for http://labs.ideo.com August 2008
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
* Modified April 2012 by Paul Stoffregen - portable to other AVR chips, use inline functions
* Modified again, June 2014 by Paul Stoffregen - support Teensy 3.1 & even more AVR chips
*
*
* This is free software. You can redistribute it and/or modify it under
* the terms of Creative Commons Attribution 3.0 United States License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
* or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*
*/

#ifndef TimerThree_h_
#define TimerThree_h_

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "config/known_16bit_timers.h"

#define TIMER3_RESOLUTION 65536UL // Timer3 is 16 bit


// Placing nearly all the code in this .h file allows the functions to be
// inlined by the compiler. In the very common case with constant values
// the compiler will perform all calculations and simply write constants
// to the hardware registers (for example, setPeriod).


class TimerThree
{


#if defined(__AVR__)
public:
//****************************
// Configuration
//****************************
void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
TCCR3B = _BV(WGM33); // set mode as phase and frequency correct pwm, stop the timer
TCCR3A = 0; // clear control register A
setPeriod(microseconds);
}
void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
const unsigned long cycles = (F_CPU / 2000000) * microseconds;
if (cycles < TIMER3_RESOLUTION) {
clockSelectBits = _BV(CS30);
pwmPeriod = cycles;
} else
if (cycles < TIMER3_RESOLUTION * 8) {
clockSelectBits = _BV(CS31);
pwmPeriod = cycles / 8;
} else
if (cycles < TIMER3_RESOLUTION * 64) {
clockSelectBits = _BV(CS31) | _BV(CS30);
pwmPeriod = cycles / 64;
} else
if (cycles < TIMER3_RESOLUTION * 256) {
clockSelectBits = _BV(CS32);
pwmPeriod = cycles / 256;
} else
if (cycles < TIMER3_RESOLUTION * 1024) {
clockSelectBits = _BV(CS32) | _BV(CS30);
pwmPeriod = cycles / 1024;
} else {
clockSelectBits = _BV(CS32) | _BV(CS30);
pwmPeriod = TIMER3_RESOLUTION - 1;
}
ICR3 = pwmPeriod;
TCCR3B = _BV(WGM33) | clockSelectBits;
}

//****************************
// Run Control
//****************************
void start() __attribute__((always_inline)) {
TCCR3B = 0;
TCNT3 = 0; // TODO: does this cause an undesired interrupt?
resume();
}
void stop() __attribute__((always_inline)) {
TCCR3B = _BV(WGM33);
}
void restart() __attribute__((always_inline)) {
start();
}
void resume() __attribute__((always_inline)) {
TCCR3B = _BV(WGM33) | clockSelectBits;
}

//****************************
// PWM outputs
//****************************
void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
unsigned long dutyCycle = pwmPeriod;
dutyCycle *= duty;
dutyCycle >>= 10;
if (pin == TIMER3_A_PIN) OCR3A = dutyCycle;
#ifdef TIMER3_B_PIN
else if (pin == TIMER3_B_PIN) OCR3B = dutyCycle;
#endif
#ifdef TIMER3_C_PIN
else if (pin == TIMER3_C_PIN) OCR3C = dutyCycle;
#endif
}
void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
if (pin == TIMER3_A_PIN) { pinMode(TIMER3_A_PIN, OUTPUT); TCCR3A |= _BV(COM3A1); }
#ifdef TIMER3_B_PIN
else if (pin == TIMER3_B_PIN) { pinMode(TIMER3_B_PIN, OUTPUT); TCCR3A |= _BV(COM3B1); }
#endif
#ifdef TIMER3_C_PIN
else if (pin == TIMER3_C_PIN) { pinMode(TIMER3_C_PIN, OUTPUT); TCCR3A |= _BV(COM3C1); }
#endif
setPwmDuty(pin, duty);
TCCR3B = _BV(WGM33) | clockSelectBits;
}
void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
if (microseconds > 0) setPeriod(microseconds);
pwm(pin, duty);
}
void disablePwm(char pin) __attribute__((always_inline)) {
if (pin == TIMER3_A_PIN) TCCR3A &= ~_BV(COM3A1);
#ifdef TIMER3_B_PIN
else if (pin == TIMER3_B_PIN) TCCR3A &= ~_BV(COM3B1);
#endif
#ifdef TIMER3_C_PIN
else if (pin == TIMER3_C_PIN) TCCR3A &= ~_BV(COM3C1);
#endif
}

//****************************
// Interrupt Function
//****************************
void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
isrCallback = isr;
TIMSK3 = _BV(TOIE3);
}
void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
if(microseconds > 0) setPeriod(microseconds);
attachInterrupt(isr);
}
void detachInterrupt() __attribute__((always_inline)) {
TIMSK3 = 0;
}
static void (*isrCallback)();

private:
// properties
static unsigned short pwmPeriod;
static unsigned char clockSelectBits;



#elif defined(__arm__) && defined(CORE_TEENSY)

#if defined(KINETISK)
#define F_TIMER F_BUS
#elif defined(KINETISL)
#define F_TIMER (F_PLL/2)
#endif

public:
//****************************
// Configuration
//****************************
void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
setPeriod(microseconds);
}
void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
const unsigned long cycles = (F_TIMER / 2000000) * microseconds;
if (cycles < TIMER3_RESOLUTION) {
clockSelectBits = 0;
pwmPeriod = cycles;
} else
if (cycles < TIMER3_RESOLUTION * 2) {
clockSelectBits = 1;
pwmPeriod = cycles >> 1;
} else
if (cycles < TIMER3_RESOLUTION * 4) {
clockSelectBits = 2;
pwmPeriod = cycles >> 2;
} else
if (cycles < TIMER3_RESOLUTION * 8) {
clockSelectBits = 3;
pwmPeriod = cycles >> 3;
} else
if (cycles < TIMER3_RESOLUTION * 16) {
clockSelectBits = 4;
pwmPeriod = cycles >> 4;
} else
if (cycles < TIMER3_RESOLUTION * 32) {
clockSelectBits = 5;
pwmPeriod = cycles >> 5;
} else
if (cycles < TIMER3_RESOLUTION * 64) {
clockSelectBits = 6;
pwmPeriod = cycles >> 6;
} else
if (cycles < TIMER3_RESOLUTION * 128) {
clockSelectBits = 7;
pwmPeriod = cycles >> 7;
} else {
clockSelectBits = 7;
pwmPeriod = TIMER3_RESOLUTION - 1;
}
uint32_t sc = FTM2_SC;
FTM2_SC = 0;
FTM2_MOD = pwmPeriod;
FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);
}

//****************************
// Run Control
//****************************
void start() __attribute__((always_inline)) {
stop();
FTM2_CNT = 0;
resume();
}
void stop() __attribute__((always_inline)) {
FTM2_SC = FTM2_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));
}
void restart() __attribute__((always_inline)) {
start();
}
void resume() __attribute__((always_inline)) {
FTM2_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);
}

//****************************
// PWM outputs
//****************************
void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
unsigned long dutyCycle = pwmPeriod;
dutyCycle *= duty;
dutyCycle >>= 10;
if (pin == TIMER3_A_PIN) {
FTM2_C0V = dutyCycle;
} else if (pin == TIMER3_B_PIN) {
FTM2_C1V = dutyCycle;
}
}
void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
setPwmDuty(pin, duty);
if (pin == TIMER3_A_PIN) {
*portConfigRegister(TIMER3_A_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
} else if (pin == TIMER3_B_PIN) {
*portConfigRegister(TIMER3_B_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
}
}
void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
if (microseconds > 0) setPeriod(microseconds);
pwm(pin, duty);
}
void disablePwm(char pin) __attribute__((always_inline)) {
if (pin == TIMER3_A_PIN) {
*portConfigRegister(TIMER3_A_PIN) = 0;
} else if (pin == TIMER3_B_PIN) {
*portConfigRegister(TIMER3_B_PIN) = 0;
}
}

//****************************
// Interrupt Function
//****************************
void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
isrCallback = isr;
FTM2_SC |= FTM_SC_TOIE;
NVIC_ENABLE_IRQ(IRQ_FTM2);
}
void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
if(microseconds > 0) setPeriod(microseconds);
attachInterrupt(isr);
}
void detachInterrupt() __attribute__((always_inline)) {
FTM2_SC &= ~FTM_SC_TOIE;
NVIC_DISABLE_IRQ(IRQ_FTM2);
}
static void (*isrCallback)();

private:
// properties
static unsigned short pwmPeriod;
static unsigned char clockSelectBits;

#undef F_TIMER

#endif
};

extern TimerThree Timer3;

#endif

@@ -0,0 +1,143 @@
#ifndef known_16bit_timers_header_
#define known_16bit_timers_header_

// Wiring-S
//
#if defined(__AVR_ATmega644P__) && defined(WIRING)
#define TIMER1_A_PIN 5
#define TIMER1_B_PIN 4
#define TIMER1_ICP_PIN 6

// Teensy 2.0
//
#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
#define TIMER1_A_PIN 14
#define TIMER1_B_PIN 15
#define TIMER1_C_PIN 4
#define TIMER1_ICP_PIN 22
#define TIMER1_CLK_PIN 11
#define TIMER3_A_PIN 9
#define TIMER3_ICP_PIN 10

// Teensy++ 2.0
#elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY)
#define TIMER1_A_PIN 25
#define TIMER1_B_PIN 26
#define TIMER1_C_PIN 27
#define TIMER1_ICP_PIN 4
#define TIMER1_CLK_PIN 6
#define TIMER3_A_PIN 16
#define TIMER3_B_PIN 15
#define TIMER3_C_PIN 14
#define TIMER3_ICP_PIN 17
#define TIMER3_CLK_PIN 13

// Teensy 3.0
//
#elif defined(__MK20DX128__)
#define TIMER1_A_PIN 3
#define TIMER1_B_PIN 4
#define TIMER1_ICP_PIN 4

// Teensy 3.1
//
#elif defined(__MK20DX256__)
#define TIMER1_A_PIN 3
#define TIMER1_B_PIN 4
#define TIMER1_ICP_PIN 4
#define TIMER3_A_PIN 32
#define TIMER3_B_PIN 25
#define TIMER3_ICP_PIN 32

// Teensy-LC
//
#elif defined(__MKL26Z64__)
#define TIMER1_A_PIN 16
#define TIMER1_B_PIN 17
#define TIMER1_ICP_PIN 17
#define TIMER3_A_PIN 3
#define TIMER3_B_PIN 4
#define TIMER3_ICP_PIN 4

// Arduino Mega
//
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TIMER1_A_PIN 11
#define TIMER1_B_PIN 12
#define TIMER1_C_PIN 13
#define TIMER3_A_PIN 5
#define TIMER3_B_PIN 2
#define TIMER3_C_PIN 3
#define TIMER4_A_PIN 6
#define TIMER4_B_PIN 7
#define TIMER4_C_PIN 8
#define TIMER4_ICP_PIN 49
#define TIMER5_A_PIN 46
#define TIMER5_B_PIN 45
#define TIMER5_C_PIN 44
#define TIMER3_ICP_PIN 48
#define TIMER3_CLK_PIN 47

// Arduino Leonardo, Yun, etc
//
#elif defined(__AVR_ATmega32U4__)
#define TIMER1_A_PIN 9
#define TIMER1_B_PIN 10
#define TIMER1_C_PIN 11
#define TIMER1_ICP_PIN 4
#define TIMER1_CLK_PIN 12
#define TIMER3_A_PIN 5
#define TIMER3_ICP_PIN 13

// Uno, Duemilanove, LilyPad, etc
//
#elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__)
#define TIMER1_A_PIN 9
#define TIMER1_B_PIN 10
#define TIMER1_ICP_PIN 8
#define TIMER1_CLK_PIN 5

// Sanguino
//
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#define TIMER1_A_PIN 13
#define TIMER1_B_PIN 12
#define TIMER1_ICP_PIN 14
#define TIMER1_CLK_PIN 1

// Wildfire - Wicked Devices
//
#elif defined(__AVR_ATmega1284P__) && defined(WILDFIRE_VERSION) && WILDFIRE_VERSION >= 3
#define TIMER1_A_PIN 5 // PD5
#define TIMER1_B_PIN 8 // PD4
#define TIMER1_ICP_PIN 6 // PD6
#define TIMER1_CLK_PIN 23 // PB1
#define TIMER3_A_PIN 12 // PB6
#define TIMER3_B_PIN 13 // PB7
#define TIMER3_ICP_PIN 9 // PB5
#define TIMER3_CLK_PIN 0 // PD0
#elif defined(__AVR_ATmega1284P__) && defined(WILDFIRE_VERSION) && WILDFIRE_VERSION < 3
#define TIMER1_A_PIN 5 // PD5
#define TIMER1_B_PIN 4 // PD4
#define TIMER1_ICP_PIN 6 // PD6
#define TIMER1_CLK_PIN 15 // PB1
#define TIMER3_A_PIN 12 // PB6
#define TIMER3_B_PIN 13 // PB7
#define TIMER3_ICP_PIN 11 // PB5
#define TIMER3_CLK_PIN 0 // PD0

// Mighty-1284 - Maniacbug
//
#elif defined(__AVR_ATmega1284P__)
#define TIMER1_A_PIN 12 // PD5
#define TIMER1_B_PIN 13 // PD4
#define TIMER1_ICP_PIN 14 // PD6
#define TIMER1_CLK_PIN 1 // PB1
#define TIMER3_A_PIN 6 // PB6
#define TIMER3_B_PIN 7 // PB7
#define TIMER3_ICP_PIN 5 // PB5
#define TIMER3_CLK_PIN 8 // PD0

#endif

#endif
@@ -0,0 +1,37 @@
#include <TimerThree.h>

// This example creates a PWM signal with 25 kHz carrier.
//
// Arduino's analogWrite() gives you PWM output, but no control over the
// carrier frequency. The default frequency is low, typically 490 or
// 3920 Hz. Sometimes you may need a faster carrier frequency.
//
// The specification for 4-wire PWM fans recommends a 25 kHz frequency
// and allows 21 to 28 kHz. The default from analogWrite() might work
// with some fans, but to follow the specification we need 25 kHz.
//
// http://www.formfactors.org/developer/specs/REV1_2_Public.pdf
//
// Connect the PWM pin to the fan's control wire (usually blue). The
// board's ground must be connected to the fan's ground, and the fan
// needs +12 volt power from the computer or a separate power supply.

const int fanPin = 14;

void setup(void)
{
Timer3.initialize(40); // 40 us = 25 kHz
Serial.begin(9600);
}

void loop(void)
{
// slowly increase the PWM fan speed
//
for (float dutyCycle = 30.0; dutyCycle < 100.0; dutyCycle++) {
Serial.print("PWM Fan, Duty Cycle = ");
Serial.println(dutyCycle);
Timer3.pwm(fanPin, (dutyCycle / 100) * 1023);
delay(500);
}
}
@@ -0,0 +1,54 @@
#include <TimerThree.h>

// This example uses the timer interrupt to blink an LED
// and also demonstrates how to share a variable between
// the interrupt and the main program.


const int led = LED_BUILTIN; // the pin with a LED

void setup(void)
{
pinMode(led, OUTPUT);
Timer3.initialize(150000);
Timer3.attachInterrupt(blinkLED); // blinkLED to run every 0.15 seconds
Serial.begin(9600);
}


// The interrupt will blink the LED, and keep
// track of how many times it has blinked.
int ledState = LOW;
volatile unsigned long blinkCount = 0; // use volatile for shared variables

void blinkLED(void)
{
if (ledState == LOW) {
ledState = HIGH;
blinkCount = blinkCount + 1; // increase when LED turns on
} else {
ledState = LOW;
}
digitalWrite(led, ledState);
}


// The main program will print the blink count
// to the Arduino Serial Monitor
void loop(void)
{
unsigned long blinkCopy; // holds a copy of the blinkCount

// to read a variable which the interrupt code writes, we
// must temporarily disable interrupts, to be sure it will
// not change while we are reading. To minimize the time
// with interrupts off, just quickly make a copy, and then
// use the copy while allowing the interrupt to keep working.
noInterrupts();
blinkCopy = blinkCount;
interrupts();

Serial.print("blinkCount = ");
Serial.println(blinkCopy);
delay(100);
}
@@ -0,0 +1,14 @@
Timer3 KEYWORD2
TimerThree KEYWORD1
initialize KEYWORD2
start KEYWORD2
stop KEYWORD2
restart KEYWORD2
resume KEYWORD2
pwm KEYWORD2
disablePwm KEYWORD2
attachInterrupt KEYWORD2
detachInterrupt KEYWORD2
setPeriod KEYWORD2
setPwmDuty KEYWORD2
isrCallback KEYWORD2
@@ -0,0 +1,16 @@
{
"name": "TimerThree",
"keywords": "timer",
"description": "Allow to use the built-in 16 bit Timer3",
"repository":
{
"type": "git",
"url": "https://github.com/PaulStoffregen/TimerThree.git"
},
"frameworks": "arduino",
"platforms":
[
"atmelavr",
"teensy"
]
}
@@ -0,0 +1,10 @@
name=TimerThree
version=1.1
author=Jesse Tane, Jérôme Despatis, Michael Polli, Dan Clemens, Paul Stoffregen
maintainer=Paul Stoffregen
sentence=Use hardware Timer3 for finer PWM control and/or running an periodic interrupt function
paragraph=
category=Timing
url=http://playground.arduino.cc/Code/Timer1
architectures=avr

Large diffs are not rendered by default.

@@ -0,0 +1,142 @@
/* $Id: Tone.h 113 2010-06-16 20:16:29Z bhagman@roguerobotics.com $
A Tone Generator Library
Written by Brett Hagman
http://www.roguerobotics.com/
bhagman@roguerobotics.com
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*************************************************/

#ifndef _Tone_h
#define _Tone_h

#include <stdint.h>

/*************************************************
* Public Constants
*************************************************/

#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978


/*************************************************
* Definitions
*************************************************/

class Tone
{
public:
void begin(uint8_t tonePin);
bool isPlaying();
void play(uint16_t frequency, uint32_t duration = 0);
void stop();

private:
static uint8_t _tone_pin_count;
uint8_t _pin;
int8_t _timer;
};

#endif
@@ -0,0 +1,17 @@
$Id: changelog.txt 120 2010-07-17 19:01:15Z bhagman@roguerobotics.com $

Tone Library

Version Modified By Date Comments
------- ----------- -------- --------
0001 B Hagman 09/08/02 Initial coding
0002 B Hagman 09/08/18 Fixed: Multiple pins.
0003 B Hagman 09/08/18 Fixed: Moved initialization from constructor to
begin().
0004 B Hagman 09/09/26 Fixed: Problems with ATmega8.
0005 B Hagman 09/11/23 Fixed: Scanned prescalars for best fit on 8 bit
timers
09/11/25 Fixed: Pin toggle method to XOR.
09/11/25 Fixed: timer0 from being excluded.
0006 B Hagman 10/03/21 Fixed: License updates, minor fixes.
B Hagman 10/07/17 Fixed: (more) problems with ATmega8 (thanks to Pete62)
@@ -0,0 +1,46 @@
// DTMF (Dual Tone Multiple Frequency) Demonstration

// http://en.wikipedia.org/wiki/Dual-tone_multi-frequency

// To mix the output of the signals to output to a small speaker (i.e. 8 Ohms or higher),
// simply use 1K Ohm resistors from each output pin and tie them together at the speaker.
// Don't forget to connect the other side of the speaker to ground!

#include <Tone.h>

Tone freq1;
Tone freq2;

const int DTMF_freq1[] = { 1336, 1209, 1336, 1477, 1209, 1336, 1477, 1209, 1336, 1477 };
const int DTMF_freq2[] = { 941, 697, 697, 697, 770, 770, 770, 852, 852, 852 };

void setup()
{
Serial.begin(9600);
freq1.begin(11);
freq2.begin(12);
}

void playDTMF(uint8_t number, long duration)
{
freq1.play(DTMF_freq1[number], duration);
freq2.play(DTMF_freq2[number], duration);
}


void loop()
{
int i;
uint8_t phone_number[] = { 8, 6, 7, 5, 3, 0 ,9 };

for(i = 0; i < sizeof(phone_number); i ++)
{
Serial.print(phone_number[i], 10);
Serial.print(' ');
playDTMF(phone_number[i], 500);
delay(600);
}

Serial.println();
delay(4000);
}
@@ -0,0 +1,222 @@
// A fun sketch to demonstrate the use of the Tone library.

// To mix the output of the signals to output to a small speaker (i.e. 8 Ohms or higher),
// simply use 1K Ohm resistors from each output pin and tie them together at the speaker.
// Don't forget to connect the other side of the speaker to ground!

// You can get more RTTTL (RingTone Text Transfer Language) songs from
// http://code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation

#include <Tone.h>

Tone tone1;

#define OCTAVE_OFFSET 0

int notes[] = { 0,
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
};

//char *song = "The Simpsons:d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g,8p,8p,8f#,8f#,8f#,8g,a#.,8c6,8c6,8c6,c6";
//char *song = "Indiana:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8e,1f,p.,g,8p,8a,8b,8p,1f6,p,a,8p,8b,2c6,2d6,2e6,e,8p,8f,8g,8p,1c6,p,d6,8p,8e6,1f.6,g,8p,8g,e.6,8p,d6,8p,8g,e.6,8p,d6,8p,8g,f.6,8p,e6,8p,8d6,2c6";
//char *song = "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5";
//char *song = "Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c.6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#,8e,c6,8e,c6,8e,2c.6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6,8a,2d6";
//char *song = "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c";
//char *song = "Xfiles:d=4,o=5,b=125:e,b,a,b,d6,2b.,1p,e,b,a,b,e6,2b.,1p,g6,f#6,e6,d6,e6,2b.,1p,g6,f#6,e6,d6,f#6,2b.,1p,e,b,a,b,d6,2b.,1p,e,b,a,b,e6,2b.,1p,e6,2b.";
//char *song = "Looney:d=4,o=5,b=140:32p,c6,8f6,8e6,8d6,8c6,a.,8c6,8f6,8e6,8d6,8d#6,e.6,8e6,8e6,8c6,8d6,8c6,8e6,8c6,8d6,8a,8c6,8g,8a#,8a,8f";
//char *song = "20thCenFox:d=16,o=5,b=140:b,8p,b,b,2b,p,c6,32p,b,32p,c6,32p,b,32p,c6,32p,b,8p,b,b,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,g#,32p,a,32p,b,8p,b,b,2b,4p,8e,8g#,8b,1c#6,8f#,8a,8c#6,1e6,8a,8c#6,8e6,1e6,8b,8g#,8a,2b";
//char *song = "Bond:d=4,o=5,b=80:32p,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d#6,16d#6,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d6,16c#6,16c#7,c.7,16g#6,16f#6,g#.6";
//char *song = "MASH:d=8,o=5,b=140:4a,4g,f#,g,p,f#,p,g,p,f#,p,2e.,p,f#,e,4f#,e,f#,p,e,p,4d.,p,f#,4e,d,e,p,d,p,e,p,d,p,2c#.,p,d,c#,4d,c#,d,p,e,p,4f#,p,a,p,4b,a,b,p,a,p,b,p,2a.,4p,a,b,a,4b,a,b,p,2a.,a,4f#,a,b,p,d6,p,4e.6,d6,b,p,a,p,2b";
//char *song = "StarWars:d=4,o=5,b=45:32p,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#.6,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#6";
//char *song = "GoodBad:d=4,o=5,b=56:32p,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,d#,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,c#6,32a#,32d#6,32a#,32d#6,8a#.,16f#.,32f.,32d#.,c#,32a#,32d#6,32a#,32d#6,8a#.,16g#.,d#";
//char *song = "TopGun:d=4,o=4,b=31:32p,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,16f,d#,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,g#";
//char *song = "A-Team:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#";
//char *song = "Flinstones:d=4,o=5,b=40:32p,16f6,16a#,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,d6,16f6,16a#.,16a#6,32g6,16f6,16a#.,32f6,32f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,a#,16a6,16d.6,16a#6,32a6,32a6,32g6,32f#6,32a6,8g6,16g6,16c.6,32a6,32a6,32g6,32g6,32f6,32e6,32g6,8f6,16f6,16a#.,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#6,16c7,8a#.6";
//char *song = "Jeopardy:d=4,o=6,b=125:c,f,c,f5,c,f,2c,c,f,c,f,a.,8g,8f,8e,8d,8c#,c,f,c,f5,c,f,2c,f.,8d,c,a#5,a5,g5,f5,p,d#,g#,d#,g#5,d#,g#,2d#,d#,g#,d#,g#,c.7,8a#,8g#,8g,8f,8e,d#,g#,d#,g#5,d#,g#,2d#,g#.,8f,d#,c#,c,p,a#5,p,g#.5,d#,g#";
//char *song = "Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,8d#";
//char *song = "Smurfs:d=32,o=5,b=200:4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8f#,p,8a#,p,4g#,4p,g#,p,a#,p,b,p,c6,p,4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8b,p,8f,p,4f#";
//char *song = "MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a#,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c.,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#.";
//char *song = "LeisureSuit:d=16,o=6,b=56:f.5,f#.5,g.5,g#5,32a#5,f5,g#.5,a#.5,32f5,g#5,32a#5,g#5,8c#.,a#5,32c#,a5,a#.5,c#.,32a5,a#5,32c#,d#,8e,c#.,f.,f.,f.,f.,f,32e,d#,8d,a#.5,e,32f,e,32f,c#,d#.,c#";
char *song = "MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d";

void setup(void)
{
Serial.begin(9600);
tone1.begin(13);
}

#define isdigit(n) (n >= '0' && n <= '9')

void play_rtttl(char *p)
{
// Absolutely no error checking in here

byte default_dur = 4;
byte default_oct = 6;
int bpm = 63;
int num;
long wholenote;
long duration;
byte note;
byte scale;

// format: d=N,o=N,b=NNN:
// find the start (skip name, etc)

while(*p != ':') p++; // ignore name
p++; // skip ':'

// get default duration
if(*p == 'd')
{
p++; p++; // skip "d="
num = 0;
while(isdigit(*p))
{
num = (num * 10) + (*p++ - '0');
}
if(num > 0) default_dur = num;
p++; // skip comma
}

Serial.print("ddur: "); Serial.println(default_dur, 10);

// get default octave
if(*p == 'o')
{
p++; p++; // skip "o="
num = *p++ - '0';
if(num >= 3 && num <=7) default_oct = num;
p++; // skip comma
}

Serial.print("doct: "); Serial.println(default_oct, 10);

// get BPM
if(*p == 'b')
{
p++; p++; // skip "b="
num = 0;
while(isdigit(*p))
{
num = (num * 10) + (*p++ - '0');
}
bpm = num;
p++; // skip colon
}

Serial.print("bpm: "); Serial.println(bpm, 10);

// BPM usually expresses the number of quarter notes per minute
wholenote = (60 * 1000L / bpm) * 4; // this is the time for whole note (in milliseconds)

Serial.print("wn: "); Serial.println(wholenote, 10);


// now begin note loop
while(*p)
{
// first, get note duration, if available
num = 0;
while(isdigit(*p))
{
num = (num * 10) + (*p++ - '0');
}

if(num) duration = wholenote / num;
else duration = wholenote / default_dur; // we will need to check if we are a dotted note after

// now get the note
note = 0;

switch(*p)
{
case 'c':
note = 1;
break;
case 'd':
note = 3;
break;
case 'e':
note = 5;
break;
case 'f':
note = 6;
break;
case 'g':
note = 8;
break;
case 'a':
note = 10;
break;
case 'b':
note = 12;
break;
case 'p':
default:
note = 0;
}
p++;

// now, get optional '#' sharp
if(*p == '#')
{
note++;
p++;
}

// now, get optional '.' dotted note
if(*p == '.')
{
duration += duration/2;
p++;
}

// now, get scale
if(isdigit(*p))
{
scale = *p - '0';
p++;
}
else
{
scale = default_oct;
}

scale += OCTAVE_OFFSET;

if(*p == ',')
p++; // skip comma for next note (or we may be at the end)

// now play the note

if(note)
{
Serial.print("Playing: ");
Serial.print(scale, 10); Serial.print(' ');
Serial.print(note, 10); Serial.print(" (");
Serial.print(notes[(scale - 4) * 12 + note], 10);
Serial.print(") ");
Serial.println(duration, 10);
tone1.play(notes[(scale - 4) * 12 + note]);
delay(duration);
tone1.stop();
}
else
{
Serial.print("Pausing: ");
Serial.println(duration, 10);
delay(duration);
}
}
}

void loop(void)
{
play_rtttl(song);
Serial.println("Done.");
while(1);
}
@@ -0,0 +1,67 @@
// Duelling Tones - Simultaneous tone generation.
// To mix the output of the signals to output to a small speaker (i.e. 8 Ohms or higher),
// simply use 1K Ohm resistors from each output pin and tie them together at the speaker.
// Don't forget to connect the other side of the speaker to ground!

// This example plays notes 'a' through 'g' sent over the Serial Monitor.
// 's' stops the current playing tone. Use uppercase letters for the second.

#include <Tone.h>

int notes[] = { NOTE_A3,
NOTE_B3,
NOTE_C4,
NOTE_D4,
NOTE_E4,
NOTE_F4,
NOTE_G4 };

// You can declare the tones as an array
Tone notePlayer[2];

void setup(void)
{
Serial.begin(9600);
notePlayer[0].begin(11);
notePlayer[1].begin(12);
}

void loop(void)
{
char c;

if(Serial.available())
{
c = Serial.read();

switch(c)
{
case 'a'...'g':
notePlayer[0].play(notes[c - 'a']);
Serial.println(notes[c - 'a']);
break;
case 's':
notePlayer[0].stop();
break;

case 'A'...'G':
notePlayer[1].play(notes[c - 'A']);
Serial.println(notes[c - 'A']);
break;
case 'S':
notePlayer[1].stop();
break;

default:
notePlayer[1].stop();
notePlayer[0].play(NOTE_B2);
delay(300);
notePlayer[0].stop();
delay(100);
notePlayer[1].play(NOTE_B2);
delay(300);
notePlayer[1].stop();
break;
}
}
}
@@ -0,0 +1,112 @@
#######################################
# Syntax Coloring Map For Tone
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

Tone KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

play KEYWORD2
stop KEYWORD2
begin KEYWORD2
isPlaying KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

NOTE_B0 LITERAL1
NOTE_C1 LITERAL1
NOTE_CS1 LITERAL1
NOTE_D1 LITERAL1
NOTE_DS1 LITERAL1
NOTE_E1 LITERAL1
NOTE_F1 LITERAL1
NOTE_FS1 LITERAL1
NOTE_G1 LITERAL1
NOTE_GS1 LITERAL1
NOTE_A1 LITERAL1
NOTE_AS1 LITERAL1
NOTE_B1 LITERAL1
NOTE_C2 LITERAL1
NOTE_CS2 LITERAL1
NOTE_D2 LITERAL1
NOTE_DS2 LITERAL1
NOTE_E2 LITERAL1
NOTE_F2 LITERAL1
NOTE_FS2 LITERAL1
NOTE_G2 LITERAL1
NOTE_GS2 LITERAL1
NOTE_A2 LITERAL1
NOTE_AS2 LITERAL1
NOTE_B2 LITERAL1
NOTE_C3 LITERAL1
NOTE_CS3 LITERAL1
NOTE_D3 LITERAL1
NOTE_DS3 LITERAL1
NOTE_E3 LITERAL1
NOTE_F3 LITERAL1
NOTE_FS3 LITERAL1
NOTE_G3 LITERAL1
NOTE_GS3 LITERAL1
NOTE_A3 LITERAL1
NOTE_AS3 LITERAL1
NOTE_B3 LITERAL1
NOTE_C4 LITERAL1
NOTE_CS4 LITERAL1
NOTE_D4 LITERAL1
NOTE_DS4 LITERAL1
NOTE_E4 LITERAL1
NOTE_F4 LITERAL1
NOTE_FS4 LITERAL1
NOTE_G4 LITERAL1
NOTE_GS4 LITERAL1
NOTE_A4 LITERAL1
NOTE_AS4 LITERAL1
NOTE_B4 LITERAL1
NOTE_C5 LITERAL1
NOTE_CS5 LITERAL1
NOTE_D5 LITERAL1
NOTE_DS5 LITERAL1
NOTE_E5 LITERAL1
NOTE_F5 LITERAL1
NOTE_FS5 LITERAL1
NOTE_G5 LITERAL1
NOTE_GS5 LITERAL1
NOTE_A5 LITERAL1
NOTE_AS5 LITERAL1
NOTE_B5 LITERAL1
NOTE_C6 LITERAL1
NOTE_CS6 LITERAL1
NOTE_D6 LITERAL1
NOTE_DS6 LITERAL1
NOTE_E6 LITERAL1
NOTE_F6 LITERAL1
NOTE_FS6 LITERAL1
NOTE_G6 LITERAL1
NOTE_GS6 LITERAL1
NOTE_A6 LITERAL1
NOTE_AS6 LITERAL1
NOTE_B6 LITERAL1
NOTE_C7 LITERAL1
NOTE_CS7 LITERAL1
NOTE_D7 LITERAL1
NOTE_DS7 LITERAL1
NOTE_E7 LITERAL1
NOTE_F7 LITERAL1
NOTE_FS7 LITERAL1
NOTE_G7 LITERAL1
NOTE_GS7 LITERAL1
NOTE_A7 LITERAL1
NOTE_AS7 LITERAL1
NOTE_B7 LITERAL1
NOTE_C8 LITERAL1
NOTE_CS8 LITERAL1
NOTE_D8 LITERAL1
NOTE_DS8 LITERAL1