[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