Pages: [1]   Go Down
Author Topic: Arduino timer interrupt  (Read 23596 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi!

Continuing with my interrupt experiements, I have a question about the timer interrupts. I use the following code to increment a counter every second:

Code:
#include <avr/interrupt.h>
#include <avr/io.h>

#define INIT_TIMER_COUNT 6
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT

int ledPin = 13;
int int_counter = 0;
volatile int second = 0;
int oldSecond = 0;
long starttime = 0;

// Aruino runs at 16 Mhz, so we have 1000 Overflows per second...
// 1/ ((16000000 / 64) / 256) = 1 / 1000
ISR(TIMER2_OVF_vect) {
  RESET_TIMER2;
  int_counter += 1;
  if (int_counter == 1000) {
    second+=1;
    int_counter = 0;
  }
};

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing timerinterrupt");
  //Timer2 Settings: Timer Prescaler /64,
  TCCR2 |= ((1<<CS22) | (0<<CS21) | (0<<CS20));  
  // Use normal mode
  TCCR2 |= (0<<WGM21) | (0<<WGM20);
  // Use internal clock - external clock not used in Arduino
  ASSR |= (0<<AS2);
  TIMSK |= (1<<TOIE2) | (0<<OCIE2);        //Timer2 Overflow Interrupt Enable  
  RESET_TIMER2;              
  sei();
  starttime = millis();
}

void loop() {
  if (oldSecond != second) {
    Serial.print(second);
    Serial.print(". ->");
    Serial.print(millis() - starttime);
    Serial.println(".");
    digitalWrite(ledPin, HIGH);
    delay(100);
    digitalWrite(ledPin, LOW);
    oldSecond = second;
  }
}

Basically, the code works. BUT: The variable "second" is only increased every two seconds. If I use

Code:
...
   if (int_counter == 500)
...

in the ISR routine, the counter is increased approximately each second (with a slight skew). I don't understand this behaviour: The Arduino runs at 16 Mhz. If I use a prescaler of /64 and an overflow occurs every 250 interrupts (256 - 6, since I reset the Timer to 6), I have 1000 interrupts per second

-> (16000000 / 64) / 250 = 1000

But this corresponds to roughly two seconds when I run the program. So: Something is wrong. Any hints?

-Mathias
Logged

Florida, USA
Offline Offline
Full Member
***
Karma: 0
Posts: 146
meow!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This is a total shot in the dark, but when you do this:

    TCCR2 |= ((1<<CS22) | (0<<CS21) | (0<<CS20));

is it possible that other bits are already set in TCCR2?  Doing a bitwise-OR between a zero and a bit that is already set to 1 will leave that bit at 1, not change it to zero.  For example, when you do the following line:

    TCCR2 |= (0<<WGM21) | (0<<WGM20);

You are not changing the value of TCCR2, no matter what its current value, because it is the same as saying:

    TCCR2 = TCCR2 | 0;

If you really want to make sure a bit is turned off, you should use &= and the bitwise not operator ~.  So why not try replacing these lines of code:

  //Timer2 Settings: Timer Prescaler /64,
  TCCR2 |= ((1<<CS22) | (0<<CS21) | (0<<CS20));  
  // Use normal mode
  TCCR2 |= (0<<WGM21) | (0<<WGM20);

with the following lines:

  //Timer2 Settings: Timer Prescaler /64,
  TCCR2 |= (1<<CS22);    // turn on CS22 bit
  TCCR2 &= ~((1<<CS21) | (1<<CS20));    // turn off CS21 and CS20 bits
  // Use normal mode
  TCCR2 &= ~((1<<WGM21) | (1<<WGM20));   // turn off WGM21 and WGM20 bits

Like I said, this is a total guess, because I have no idea what these things are, but I think this is at least closer to what you intended.   Let us know how it works...

- Don
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
This is a total shot in the dark,


But a good one.

Code:
for (int i=0; i<100; i++) {
   Serial.println("I will think before I code.");
}

;-) It works like a charm now, you can find the full code here:

http://gonium.net/md/2006/12/27/i-will-think-before-i-code/

Thanks!

-Mathias
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Gonium,
In your example, it only allows for 1000 interrupts per second. Is there a way to increase this value for applications that require more interrupts? Writing an 8bit software pwm requires a minimum of 256 interrupts to complete the pwm, making less than 4 pwm cycles per second. This doesn't seem to be fast enough to make an led look like its not blinking.

It seems timer1 is a 16bit timer, instead of timer2 which is 8 bits, but I am not certain on how to port your code to use this other timer.    Could you, or someone else, possibly give an example of this code using timer1 instead of timer2?

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi yiyi,

Quote
In your example, it only allows for 1000 interrupts per second. Is there a way to increase this value for applications that require more interrupts? Writing an 8bit software pwm requires a minimum of 256 interrupts to complete the pwm, making less than 4 pwm cycles per second. This doesn't seem to be fast enough to make an led look like its not blinking.

It seems timer1 is a 16bit timer, instead of timer2 which is 8 bits, but I am not certain on how to port your code to use this other timer.    Could you, or someone else, possibly give an example of this code using timer1 instead of timer2?

I am not sure whether I understand you correctly. In general, it should be pretty easy to convert my code to use timer1 - just set the right bits for timer1, and use the same interrupt handler routine. You can find the correct bits in the datasheet.

BUT: If you want to do PWM, this might not be the easiest way. The timer hardware has pre-build wires to do PWM - basically, you can tell the hardware to do the PWM with a given frequency for you. This is also the reason why pin 9-11 can do PWM - there are three timers in the ATMega8.

Have you read the Arduino tutorial? I think this might be what you're looking for...

http://www.arduino.cc/en/Tutorial/DimmingLEDs
http://www.arduino.cc/en/Reference/AnalogWrite
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've gotten the hardware pwm to work, but now I am trying to learn more about how interrupts and the timers work. So I am trying to create a software PWM routine to control more LEDs than the 3 pins available. Also I would like higher resolution than the 8 bits the hardware PWMs give.

After playing around with this more the past couple of days, I seem to be able to get it to work correctly using the overflow interrupt of timer1, but I think what I need to be using is the compare interrupt so that I can interrupt every X amount of time. where X is 256 * pwm cycles/second ( I think I read somewhere that I need to do around 100 full pwm cycles per second).

Using the compare mode of timer1, though, I can't seem to get it to work properly. I've gone over the datasheet many times, trying to understand all of it, but in this stage of my microcontroller learning, its hard to figure out what bits I need to turn on and what bits need to be turned off and in what register and if I need to reset TCCNT1 myself or if that happens automatically, or if I need to turn off interrupts while I'm  in the interrupt routine.

This is definately not the easiest way to do it, but its a good thing to know, and interrupts are fairly important for larger projects, so I'm trying to learn them early for smaller projects, so I can't work with them later in a bigger project.

Does this make more sense?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
l'oisivete est mere de tous les vices
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hey yiyi, i've been experimenting with timers lately. it's really fantastic. the following code works good for using timer1 or timer2 in CTC mode. the spec sheet of the atmega8 (that's what i'm using, if you're on m168, it might be a bit different) is really well written and explains a lot.
the code below will automatically toggle the pins at the given frequencies (400 and 415hz) thus generating square waves that you can run through an RC filter to smooth them out. the freq is Fosc/(2*prescaler*TCCRn)

Code:
#include <avr/interrupt.h>  

void setup() {  
  pinMode(9, OUTPUT); // OC1A = output of CTC mode for timer1
  pinMode(11, OUTPUT); // OC2 = same for timer2
  TIMSK = 0x00;  // all interupts OFF
  TCCR1A = 0x40; // 0100 0000
  TCCR1B = 0x09; // 0000 1001 this line and previous = CTC mode, toggle on compare, prescaler = 1
  OCR1A = 19275; // ~415Hz
  TCCR2 = 0x1E; // 0001 1110 = CTC mode, toggle on compare, prescaler = 256
  OCR2 = 77;    // ~400Hz
  TIMSK = 0x90; // 1001 0000 = 0CIE1 ON, OCIE2 ON
}  
  
void loop()
{  
}

don't forget to set your pins as output because i first forgot and scratched my head for a while before knowing where the pb came from smiley

for some strange reason, it works perfectly on timer2 but outputs a freq twice as high as what it should be on timer1. not sure why. if anybody can explain, that's be great. have fun.
« Last Edit: June 19, 2007, 01:08:26 pm by tateu » Logged

Enschede, the Netherlands
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I've been experimenting with timers as well, but I couldn't get the above code to work. The reason: the code is for the Atmega8, while new Arduino boards come with a Arduino168. Slight difference.

To prevent other people who use the search to step into the same pitfall, here's the minimalistic code I came up with:

Code:
#include <avr/interrupt.h>  
#include <avr/io.h>

//Timer2 overflow interrupt vector handler, called (16,000,000/256)/256 times per second
ISR(TIMER2_OVF_vect) {
  //let 10 indicates interrupt fired
  digitalWrite(10,true);
};  

void setup() {
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);

  //Timer2 Settings: Timer Prescaler /256, WGM mode 0
  TCCR2A = 0;
  TCCR2B = 1<<CS22 | 1<<CS21;

  //Timer2 Overflow Interrupt Enable  
  TIMSK2 = 1<<TOIE2;

  //reset timer
  TCNT2 = 0;

  //led 9 indicate ready
  digitalWrite(9,true);
}

void loop() {
}

This is for the Atmega168-arduino's! And for the record: I'm using Arduino IDE v0008, and firmware v1.15.

When run, a led (or whatever) connected on pin 9 lights directly after initalisation. When the timer fires, led 10 lights up. The timer is repetitive, it keeps firing.

I'm aware of the FrequencyTimer2 lib, but this code is a bit more compact and doesn't use the PWM-mode. People who need to generate a pulse/clock on the output should definately have a look at the FT2-lib.
« Last Edit: August 03, 2007, 06:26:22 pm by Fuzzillogic » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 27
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using the code given above very successfully, but I now need to integrate it into existing code and I have some questions.  I already asked these under the syntax part of the forum, but perhaps this is the more appropriate place.
 
1.  Can someone give me urls for references that explain in detail how the timer interrupt works?  In particular what all of the different flags and registers do?  I'm using things like TIMSK2 and CCS21 for example but don't have any sort of reference for them and so don't know what they do are what they mean.
 
2.  How many timer interrupts are available and how does one use more than one of them?
 
3.  Do I have to disable anything in the arduino code in order to avoid conflicts?  I am not using pwm at all.
 
4.  Can I use timer interrupts and external interrupts at the same time?
 
Any information on this would be great!!  Thanks in advance.
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 9
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Unfortunately, the only source that I know for this information is the rather long and unwieldy datasheet for the ATmega168: http://www.atmel.com/dyn/resources/prod_documents/doc2545.pdf
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 27
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you, that's exactly what I was looking for as a reference. smiley
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, I'm new on Arduino, and I want to use this program, but I have an Arduino MEGA 2560. This program is useful for MEGA 2560???

Thanks for your time. ;D
Logged

Pages: [1]   Go Up
Jump to: