Here's a tested example:
/* ---------------------------------------------------------------
Timer 1 setup
--------------------------------------------------------------- */
namespace Timer1
{
// TCCR1A, TCCR1B
const byte Modes [16] [2] =
{
{ 0, 0 }, // 0: Normal, top = 0xFFFF
{ _BV (WGM10), 0 }, // 1: PWM, Phase-correct, 8 bit, top = 0xFF
{ _BV (WGM11), 0 }, // 2: PWM, Phase-correct, 9 bit, top = 0x1FF
{ _BV (WGM10) | _BV (WGM11), 0 }, // 3: PWM, Phase-correct, 10 bit, top = 0x3FF
{ 0, _BV (WGM12) }, // 4: CTC, top = OCR1A
{ _BV (WGM10), _BV (WGM12) }, // 5: Fast PWM, 8 bit, top = 0xFF
{ _BV (WGM11), _BV (WGM12) }, // 6: Fast PWM, 9 bit, top = 0x1FF
{ _BV (WGM10) | _BV (WGM11), _BV (WGM12) }, // 7: Fast PWM, 10 bit, top = 0x3FF
{ 0, _BV (WGM13) }, // 8: PWM, phase and frequency correct, top = ICR1
{ _BV (WGM10), _BV (WGM13) }, // 9: PWM, phase and frequency correct, top = OCR1A
{ _BV (WGM11), _BV (WGM13) }, // 10: PWM, phase correct, top = ICR1A
{ _BV (WGM10) | _BV (WGM11), _BV (WGM13) }, // 11: PWM, phase correct, top = OCR1A
{ 0, _BV (WGM12) | _BV (WGM13) }, // 12: CTC, top = ICR1
{ _BV (WGM10), _BV (WGM12) | _BV (WGM13) }, // 13: reserved
{ _BV (WGM11), _BV (WGM12) | _BV (WGM13) }, // 14: Fast PWM, TOP = ICR1
{ _BV (WGM10) | _BV (WGM11), _BV (WGM12) | _BV (WGM13) }, // 15: Fast PWM, TOP = OCR1A
}; // end of Timer1::Modes
// Activation
// Note: T1 is pin 11, Arduino port: D5
enum { NO_CLOCK, PRESCALE_1, PRESCALE_8, PRESCALE_64, PRESCALE_256, PRESCALE_1024, T1_FALLING, T1_RISING };
// what ports to toggle on timer fire
enum { NO_PORT = 0,
// pin 15, Arduino port: D9
TOGGLE_A_ON_COMPARE = _BV (COM1A0),
CLEAR_A_ON_COMPARE = _BV (COM1A1),
SET_A_ON_COMPARE = _BV (COM1A0) | _BV (COM1A1),
// pin 16, Arduino port: D10
TOGGLE_B_ON_COMPARE = _BV (COM1B0),
CLEAR_B_ON_COMPARE = _BV (COM1B1),
SET_B_ON_COMPARE = _BV (COM1B0) | _BV (COM1B1),
};
// choose a timer mode, set which clock speed, and which port to toggle
void setMode (const byte mode, const byte clock, const byte port)
{
if (mode < 0 || mode > 15) // sanity check
return;
// reset existing flags
TCCR1A = 0;
TCCR1B = 0;
TCCR1A |= (Modes [mode] [0]) | port;
TCCR1B |= (Modes [mode] [1]) | clock;
} // end of Timer1::setMode
} // end of namespace Timer1
const byte LED = 8;
volatile boolean fired = false;
ISR(TIMER1_COMPA_vect)
{
fired = true;
} // end of TIMER1_COMPA_vect
void setup()
{
pinMode (LED, OUTPUT);
// set up Timer 1
Timer1::setMode (4, Timer1::PRESCALE_64, Timer1::NO_PORT);
TCNT1 = 0; // reset counter
OCR1A = 4999; // compare A register value
TIFR1 |= _BV (OCF1A); // clear interrupt flag
TIMSK1 = _BV (OCIE1A); // interrupt on Compare A Match
} // end of setup
void loop ()
{
if (fired)
{
digitalWrite (LED, HIGH);
digitalWrite (LED, LOW);
// do your stuff here
fired = false;
}
} // end of loop
This uses my Timer1 "helper" namespace and function to set up the timer. What it is doing is setting up Timer 1 with a prescaler of 64 and a counter of 5000 (zero relative, 4999). This gives a period of:
62.5 * 64 * 5000 = 20000000 nS
That is, 20 mS.
Then it uses the compare A interrupt to set a flag. In loop you just wait for the flag to be set. Then you process, and clear the flag. Measuring the time between pulses on pin 8, I got 20.004 mS, which is pretty close.
The same code runs on the Mega2560 and the Atmega328.
There might be a slight delay (a microsecond or two) before the flag is noticed, but since the hardware timer is clocking out the interrupts, the delay will not be cumulative.