[McHUG] Arduino Timer help

John Yost k3yjp at yahoo.com
Wed Oct 6 19:48:43 EDT 2010


I think I have timers under control using both the Output Compare and Overflow 
methods and give predictable results.

One thing I don't understand is why, using the same count values, that the 
Output Compare( 1 sec per interrupt) 

is half the speed of the Overflow method( 500ms/interrupt).   Sketch is below 
that I used for testing, blinking an led with a timing loop, one with timer1 
overflow 

interrupt and one using timer2 output compare interrupt.  All should blink at 
500ms.

I'm sure I missed something, but since I know what to expect not a big deal just 
a minor mystery to me.

Thanks again Steve for your help.  Your example put me straight.

John
K3YJP

//* Blink without Delay


// constants won't change. Used here to 
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin
const int toggle_IO1 = 12;
const int toggle_IO2 = 11;

// Variables will change:
int ledState = LOW;             // ledState used to set the LED

long previousMillis = 0;        // will store last time LED was updated
volatile unsigned int timer1Cnt = 65536 - (2 * 156);  // 500ms at 256 prescale = 
(CPU Clk / prescale) * time interval)  for 16 bit timer
volatile byte timer2Cnt =156;            // 10ms at 1024 prescale = (CPU Clk / 
prescale) * time interval)  for 8 bit timer
volatile byte interruptCnt =0;
volatile byte interrupt1Cnt =0;

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 500;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT); 
  pinMode(toggle_IO1, OUTPUT);
  pinMode(toggle_IO2, OUTPUT);
  digitalWrite(ledPin, LOW);
  digitalWrite(toggle_IO1, LOW);
  digitalWrite(toggle_IO2, LOW);

// setup timer1 normal mode 1024 prescale  overflow interrupt
// 
  timer1Cnt = 65536 - (16000000 / 1024) * (.01);
  TCCR1A = 0;                           // set timer to normal mode
  TCCR1B = (1<<CS12) | (0<<CS11) | (1<<CS10); // 1024 prescale
  TCNT1=timer1Cnt;                      // set counter to starting count - in 
normal mode timer counts up to 0xFFFF
  TIFR1 |= (1<<TOV1);
//Timer1 Overflow Interrupt Enable   
  TIMSK1 |= 1<<TOIE1;
  
//setup timer2 normal mode 1024 prescal output compare interrupt
  timer2Cnt = 256 - (16000000 / 1024) * (.01);
  TCCR2A = 0;
  TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20; // 1024 prescale
  TIFR2 |= (1<<OCF2A); 
  TIMSK2 |= (1<<OCIE2A);
  OCR2A= TCNT2 + timer2Cnt;
}  
void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

// have each interrupt routine blink 500ms rate
// each should be running at 10 ms rate so 50 interrupts needed to make 500ms
ISR(TIMER1_OVF_vect) {
  interrupt1Cnt++;
  if (interrupt1Cnt > 49) {
  //Toggle the IO pin to the other state.
  digitalWrite(toggle_IO1,!digitalRead(toggle_IO1));
    interrupt1Cnt = 0;
  }
    TCNT1 = timer1Cnt; // reset counter
}
ISR(TIMER2_COMPA_vect) {

  //Toggle the IO pin to the other state.
  interruptCnt++;
  if (interruptCnt > 49) {
  digitalWrite(toggle_IO2,!digitalRead(toggle_IO2));
  interruptCnt = 0;
  }
    OCR2A = timer2Cnt; // reset counter 
}




----- Original Message ----
From: "n3sb at qis.net" <n3sb at qis.net>
To: mchug at mailman.qth.net
Sent: Wed, September 22, 2010 7:13:48 AM
Subject: Re: [McHUG] Arduino Timer help

Hi John;

Two additional items:

There's one comment in the code that's misleading. The comment
    //Timer1 Overflow Interrupt Enable
should really be
    //Timer1 Output Compare Interrupt Enable

Also - I had some fits initially getting the timers to work too.  
Fortunately there's a simulator in Atmel's AVR Studio that can read  
the elf files generated by the Arduino IDE. It works quite well -  
showing all the details in each of the registers, as well as the  
timers & counters doing their thing.

73; Steve, N3SB


Quoting John Yost <k3yjp at yahoo.com>:

> That's great Steve.
> I was working along the same line of thought but was missing the setup of the
> TIFR register and setting the wrong bit in TIMSK.
> Your code is more elegant than mine but I'm getting there.
>
>
> Now to go interrupt something.
>
> Thank Steve and I'll post how I make out with it.
>
> John
>
>
>
> ----- Original Message ----
> From: "n3sb at qis.net" <n3sb at qis.net>
> To: mchug at mailman.qth.net
> Sent: Tue, September 21, 2010 8:13:56 PM
> Subject: Re: [McHUG] Arduino Timer help
>
> Hi John;
>
> Here's an Arduino program that uses the 16 bit timer to generate an
> interrupt at 26400 Hz. You should be able to adapt it to your needs.
>
> It uses one of the Output Compare registers to generate an interrupt
> when the 16 bit timer, running at 16 MHz, matches the output compare
> value. In the interrupt routine the program adds the right delay value
> to the current output compare register value, and sets up for the next
> interrupt.
>
> Using this technique you can create all kinds of useful, very accurate
> time delays. The interrupt routine itself will NOT cause a cumulative
> time error because the timer itself keeps running.
>
> NOTE: Be careful if you modify variables in the interrupt routine that
> are used elsewhere in the program. You'll need to declare those
> variables as volatile so that the compiler always fetches a new copy
> of the variable from memory for your calculations.
>
> 73; Steve, N3SB
>
>
>
> // Program interrupt1 written November 15, 2008 N3SB
> //
> // This program sets up a 26400 Hz interrupt on an Arduino (ATMega168 based)
> // From that interrupt, timing for other packet functions can be
> developed (1200 Hz tone, 2200 Hz tone, and 1200 baud bit rate).
>
> // Macro and other defines
>
> // Variable defines
> unsigned int intcount = 0;
> unsigned char ledon = 0;
> unsigned char count1200 = 0;
> unsigned char count2200 = 0;
> unsigned char on1200 = 0;
> unsigned char on2200 = 0;
>
> // Pin Defines
> int ledpin = 13;               // Arduino pin used by the LED
> int pin2200 = 12;              // pin where the 2200 Hz signal will appear
> int pin1200 = 11;              // pin where the 1200 Hz signal will appear
>
> // Arduino runs at 16 MHz; to get to 26400 Hz we count 606 clocks
> // 16000000 / 606 = 26402.64 Hz (within 0.01%)
> //
> // We will use the 16 bit timer 1 hardware, and the COMPA interrupt.
>
> ISR(TIMER1_COMPA_vect)
> {
>    count1200++;                  // Counter for 1200 Hz tone. Toggles
> every 11 interrupts at 26400 Hz, or 2400 times per second.
>    if (count1200 == 11)
>    {
>      count1200 = 0;
>      if (on1200 == 0)
>      {
>        digitalWrite(pin1200, HIGH);
>        on1200 = 1;
>      }
>      else
>      {
>        digitalWrite(pin1200, LOW);
>        on1200 = 0;
>      }
>    }
>
>    count2200++;                  // Counter for 2200 Hz tone. Toggles
> every 6 interrupts at 26400 Hz, or 4400 times per second.
>    if (count2200 == 6)
>    {
>      count2200 = 0;
>      if (on2200 == 0)
>      {
>        digitalWrite(pin2200, HIGH);
>        on2200 = 1;
>      }
>      else
>      {
>        digitalWrite(pin2200, LOW);
>        on2200 = 0;
>      }
>    }
>
>    intcount++;                   // Counter for 1 Hz LED Blink
>    if (intcount == 26400)
>    {
>      intcount = 0;
>      if (ledon == 0)
>      {
>        digitalWrite(ledpin, HIGH);
>        ledon = 1;
>      }
>      else
>      {
>        digitalWrite(ledpin, LOW);
>        ledon = 0;
>      }
>    }
>
>    OCR1A = OCR1A + 606;          // Set Output Compare register for
> the next interrupt in 606 cycles
> }  // end of timer interrupt routine
>
> void setup() {
>    pinMode(ledpin, OUTPUT);       // configure LED pin for output
>    pinMode(pin1200, OUTPUT);
>    pinMode(pin2200, OUTPUT);
>
>    digitalWrite(ledpin, LOW);     // turn off LED
> //  Serial.begin(9600);
> //  Serial.println(" ");
> //  Serial.println("Program Interrupt1 - 15 November 2008 - N3SB");
> //  Serial.println(" ");
>
> //Timer1 Settings: Normal Mode, Timer Prescaler / 1
>
>    TCCR1A = 0;
>    TCCR1B = 1;
>
>    //Timer1 Overflow Interrupt Enable
>    TIFR1  |= (1<<OCF1A);       // Clear any pending output compare A  
> interrupts
>    TIMSK1 |= (1<<OCIE1A);      // Timer1 Output Compare A Interrupt Enable
>
>    OCR1A = TCNT1 + 606;
>
>    TIMSK0 = 0;                 // Disable Timer0 interrupts (enabled
> in Arduino setup code)
>
>    sei();
> }    // end of Arduino setup structure
>
> void loop()
> {
>    delay(1000);        // give the main loop something to do.
> }  // end of Arduino loop structure



      


More information about the McHUG mailing list