Cascading Timers to Create a Long Delay

cascade
Here is a demonstration program that runs on an Arduino which creates a 1 minute long delay by cascading timers. The procedure is outlined in Atmel Application Note AVR133.

I’ve set timer #1 up to toggle the OCR1A pin (D9) and wired that to the T0 pin (D4) which clocks timer #0. Then I put the arduino to sleep and wait for the timer #0 interrupt to wake it. The values I’m using should toggle the pin 13 LED at a 1 minute frequency.

A much longer delay is easily possible by increasing the counter values and the timer #1 prescaler. For example, with a 1024 prescale and maximum counter values, a delay of over 35 minutes is possible (with a 16MHz system clock).

Note: the reprogrammed timer 0 and 1 trashes the original arduino functions of these timers.

// AVR 133: Atmel Application Note Long Delay Generation Demo
// Blinks LED on a 1 minute period:
// T = 2/Fs x T1P x OCR1A x (256 - TCNT0)
// T = 2/16000000x256x7500x(256-6)
// T = 60 or 1 minute
//
// connect arduino D9 to D4: 
//  T0   = PD4 (Arduino D4 as input)
//  OC1A = PB1 (Arduino D9 as output)
#include <avr/sleep.h>
#include <avr/power.h>

void setup() {
  cli();
  
  //set pins
  DDRB |= (1<<PINB1) | (1<<PINB5); //set arduino D9 and D13 as outputs
  PORTB &= ~(1<<PINB1);            //set D9 low
  PORTD &= ~(1<<PIND4);            //set D4 low

  //timer #1 toggles OCR1A on TCNT1=0 in turn toggling T0
  TCCR1A = (1<<COM1A0); //TCCR1A toggle OC1A on compare match
  TCCR1B = 0;
  TCCR1C = 0;
  OCR1A = 7500;       //output compare register on division ratio of 7500
  TIMSK1 = 0;

  //timer #0 fires interrupt when TCNT0=0 waking arduino 
  TCCR0A = 0;
  TCCR0B = 0;
  TIMSK0 = (1<<TOIE0);  //enable timer0 interrupt
  
  sei();
}

void loop() {
  //toggle led
  PORTB ^= (1<<PINB5); //toggle led pin 

  //reset timers
  TCNT0 = 6;
  TCCR0B = (1<<CS00) | (1<<CS01) | (1<<CS02); //external source (t0) rising edge
  TCNT1 = 0UL;
  TCCR1B = (1<<WGM12) | (1<<CS12); //CTC mode 4 and 256 prescaler

  //sleep and power down setup
  set_sleep_mode(SLEEP_MODE_IDLE);
  sleep_enable();
  power_adc_disable();
  power_spi_disable();
  power_timer2_disable();
  power_twi_disable();
  sleep_mode();
  //go to sleep here
  sleep_disable();

  //wake upon timer #0 interrupt here
  power_all_enable();
 
  //stop timers
  TCCR1B = 0;
  TCCR0B = 0; 
}
Advertisements

About Jim Eli

µC experimenter
This entry was posted in Uncategorized and tagged , , , , , , . Bookmark the permalink.

4 Responses to Cascading Timers to Create a Long Delay

  1. Ron says:

    Thank you!
    I have been working through the meaning of everything in application note and the data sheet (ATmega16/32U4).
    I have it working on a Duemilanove.
    I just connected DIGITAL 9 to DIGITAL 4 and uploaded the program copied from above..
    The on-board LED toggles once per minute.
    But my YUN and Leonardo won’t do it.
    Don’t know why yet.

    • Jim Eli says:

      @Ron, This code is for an AtMega168/328 chip and directly manipulates the timer registers. The Leonardo and Yun use a 32U4 based chip and while not completely certain, the registers will probably need to be tweaked. I’m sorry but I can’t help much.

      • Ron Hartikka says:

        I have it working on Leonardo now.

        // AVR 133: Atmel Application Note Long Delay Generation Demo // Blinks LED on a 1 minute period: // T = 2/Fs x T1P x OCR1A x (256 – TCNT0) // T = 2/16000000x256x7500x(256-6) // T = 60 or 1 minute // // connect arduino D9 to D4: // connect Leonardo/Yun D9 to D6

        // T0 = PD4 (Arduino board D4 as input) or Leonardo D6 which is 32U4’s PD7 // OC1A = PB1 (Arduino board D9 as output) or leonardo D9 which is 32U4’s PB5

        #include #include

        void setup() { cli();

        // Configure Outputs. TIMER1 will toggle OC1A. loop() will toggle on-board LED @ D13

        //DDRB |= (1<<PINB1) | (1< M328 PB1 -> board D9. PB5 -> board D13 DDRB |= (1<<PINB5) | (1< 32U4 PB5 -> board D9, PB7 -> board D13

        // Set Pins

        //PORTB &= ~(1<<PINB1); //not Leonardo or Yun: D9 low PORTB &= ~(1<<PINB5); // Leonardo Or Yun: D9 low

        // works ok (same) without this line – at least with Leonardo //PORTD &= ~(1<<PIND4); //not Leonardo or Yun: set D4 low //PORTC &= ~(1<<PINC7); // Leonardo or Yun: set D6 low. This is T0.

        //timer #1 toggles OCR1A on TCNT1=0 in turn toggling T0 TCCR1A = (1<<COM1A0); //TCCR1A toggle OC1A on compare match TCCR1B = 0; TCCR1C = 0; OCR1A = 7500; //output compare register on division ratio of 7500 TIMSK1 = 0;

        //timer #0 fires interrupt when TCNT0=0 waking arduino TCCR0A = 0; TCCR0B = 0; TIMSK0 = (1<<TOIE0); //enable timer0 interrupt

        sei(); }

        void loop() { //toggle led //PORTB ^= (1<<PINB5); // not Leonardo or Yun: toggle led pin PORTC ^= (1<<PINC7); // Leonardo or Yun: toggle led pin

        //reset timers TCNT0 = 6; TCCR0B = (1<<CS00) | (1<<CS01) | (1<<CS02); //external source (t0) rising edge TCNT1 = 0UL; TCCR1B = (1<<WGM12) | (1<<CS12); //CTC mode 4 and 256 prescaler

        //sleep and power down setup set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); power_adc_disable(); power_spi_disable(); power_timer2_disable(); power_twi_disable(); sleep_mode(); //go to sleep here sleep_disable();

        //wake upon timer #0 interrupt here power_all_enable();

        //stop timers TCCR1B = 0; TCCR0B = 0; }

      • Jim Eli says:

        Thanks for posting.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s