9
\$\begingroup\$

I am trying to create a time delay interrupt with Arduino. I would like to use the interrupts() function, because it is an internal interrupt.

Example: Let's say, I would like to make a light blink on and off, with only the timing of the interrupt.

There is sample code, but it uses external interrupts (attachInterrupt()). I would like to remain using the internal interrupts.

\$\endgroup\$
  • 2
    \$\begingroup\$ I think that the point that also Kortuk showed is that attachInterrupt is an abstract thing, you're not attaching any external component :) \$\endgroup\$ – clabacchio Feb 9 '12 at 8:06
  • \$\begingroup\$ This article might help you. engblaze.com/… \$\endgroup\$ – Seth Archer Brown Feb 10 '12 at 22:48
10
+100
\$\begingroup\$

Noah Stahl's blog has an example of blinking a LED with Timer2. With that and the data sheet, you should be able to adapt it to whichever interrupt you want to use -- i.e., the interrupt whose normal function you can most afford to give up or are willing to modify. Timer2 is usually used for some PWM functions.

His example cites the ATmega2560; I can confirm that it works with an ATmega328p as well. Look around his site for more useful Arduino interrupt examples.

Edit:

Here's my slightly edited -- mostly in the comments -- version of Noah's code. Call Timer2init() from the Arduino setup() function after you initialize any related data-structures or hardware, because timing - and interrupting - will begin once you do.

F/ex, I used it to multiplex a 3-digit 7-segment display so I before initializing the timer, I initialized the display I/O registers and blanked the display data in the place where the ISR will look for it.

There is a table in the comments of some useful timing data from the data-sheet and my own calculations for reference to set up another timing scheme.

The ISR() macro takes care of creating interrupt entry- and exit-code for an ISR instead a normal function's entry and exit, and of linking it with the proper interrupt vector. The rest of that function is 1) the code to be run at each interrupt, and 2) the code code to reset the timer for the next interrupt.

As written, this should drop in to a .pde or .ino sketch (or a .cpp file, if you use eclipse, f/ex). The sketch needs to #define LEDPIN, and setup() needs to call Timer2init(). The loop function may be empty or not; the LED should start flashing on download (well, literally, after Timer2init() is called).

/*
 * From sample interrupt code published by Noah Stahl on his blog, at:
 * http://arduinomega.blogspot.com/p/arduino-code.html
 * 
 */


/*** FUNC

Name:           Timer2init

Function:       Init timer 2 to interrupt periodically. Call this from 
                the Arduino setup() function.

Description:    The pre-scaler and the timer count divide the timer-counter
                clock frequency to give a timer overflow interrupt rate:

                Interrupt rate =  16MHz / (prescaler * (255 - TCNT2))

        TCCR2B[b2:0]   Prescaler    Freq [KHz], Period [usec] after prescale
          0x0            (TC stopped)     0         0
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000


Parameters: void

Returns:    void

FUNC ***/

void Timer2init() {

    // Setup Timer2 overflow to fire every 8ms (125Hz)
    //   period [sec] = (1 / f_clock [sec]) * prescale * (255-count)
    //                  (1/16000000)  * 1024 * (255-130) = .008 sec


    TCCR2B = 0x00;        // Disable Timer2 while we set it up

    TCNT2  = 130;         // Reset Timer Count  (255-130) = execute ev 125-th T/C clock
    TIFR2  = 0x00;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag
    TIMSK2 = 0x01;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable
    TCCR2A = 0x00;        // Timer2 Control Reg A: Wave Gen Mode normal
    TCCR2B = 0x07;        // Timer2 Control Reg B: Timer Prescaler set to 1024
}



/*** FUNC

Name:       Timer2 ISR

Function:   Handles the Timer2-overflow interrupt

Description:    Maintains the 7-segment display

Parameters: void

Returns:    void

FUNC ***/

ISR(TIMER2_OVF_vect) {
    static unsigned int led_state = 0; // LED state

    led_state = !led_state;         // toggles the LED state
    digitalWrite(TOGGLE_PIN, led_state);

    TCNT2 = 130;     // reset timer ct to 130 out of 255
    TIFR2 = 0x00;    // timer2 int flag reg: clear timer overflow flag
};
\$\endgroup\$
  • \$\begingroup\$ (@Kortuk: The comment you refer to was my observation of several commentators here and not aimed at you personally and it was unnecessary. I apologize and I've removed it.) I expanded on my answer as you suggested and I hope that it's now not only demonstrative, but instructive as as well. It includes comments I've written into the code for my own use (meaning: If I can understand them 6 months from now, someone else will be able to, too), as well as a few "how to use" instructions in the answer. Thanks for your suggestions. \$\endgroup\$ – JRobert Feb 9 '12 at 21:02
  • \$\begingroup\$ Note that prescales of 32 and 128 are not available for timer0 and timer1 (atleast with atmega328). \$\endgroup\$ – tuupola Feb 12 '12 at 19:50
  • \$\begingroup\$ That's good to know - thanks. I use this for Timer2 (so far) and it's basically a drop-in. \$\endgroup\$ – JRobert Feb 13 '12 at 1:37
5
\$\begingroup\$

The attachInterrupt() function actually is attaching an interrupt to an external state change on a pin, it does not have any other options.

On the same page the mode options are listed as:

mode defines when the interrupt should be triggered. Four contstants are predefined as valid values:

  • LOW to trigger the interrupt whenever the pin is low,
  • CHANGE to trigger the interrupt whenever the pin changes value
  • RISING to trigger when the pin goes from low to high,
  • FALLING for when the pin goes from high to low.

Sorry to be the bearer of bad news, that is one of the first things I looked for also.

\$\endgroup\$
  • \$\begingroup\$ I think that he means that he want to use an internal timer, instead of an external device...but I don't know Arduino very well, so I can't say if it's possible \$\endgroup\$ – clabacchio Feb 9 '12 at 8:08
  • \$\begingroup\$ @clabacchio, I am saying that the only option is to use an external trigger, there is not internal timer function. \$\endgroup\$ – Kortuk Feb 9 '12 at 8:46
  • \$\begingroup\$ Ah, good :) but at least do the Arduino boards have any timers? \$\endgroup\$ – clabacchio Feb 9 '12 at 8:48
  • \$\begingroup\$ Yes, that is how they accomplish things like delay. \$\endgroup\$ – Kortuk Feb 9 '12 at 9:43
  • 1
    \$\begingroup\$ @icarus74 ATMega328 really has 3 timers (one is 16b and two are 8b) but all of them are used by Arduino. One is used for functions like delay() and millis() and all three are used for PWM (you can find more information in function 'init()', file 'wiring.c' in Arduino IDE). \$\endgroup\$ – vasco Feb 9 '12 at 14:08
2
\$\begingroup\$

This article on PWM will clear lot of your doubts regarding usage of Arduino timers. There are two 8-bit timers, and one 16-bit timer on Arduino. There is no high-level API to hook ISR function directly onto the timers, that is shipped with the Arduino SDK (i.e. as a standard library), but a somewhat lower-level method of setting Special-Function-Registers and bit-arithmetic/operations on them. However there is a user contributed library called Timer one.

\$\endgroup\$
  • \$\begingroup\$ There are actually several different timer combinations possible depending on which Arduino is being referred to. Answer is misleading. \$\endgroup\$ – Seemingly So Jan 6 '13 at 16:04
  • \$\begingroup\$ @SeeminglySo, care to elaborate ? If you are talking about Arduino hardware, note that the answer is in context of the question and also the time when the question is asked. \$\endgroup\$ – icarus74 Jan 10 '13 at 7:18
  • \$\begingroup\$ The Arduino Mega (ATmega1280 based) was released on 26 March 2009, and the Mega 2560 (ATmega2560) was released on 24 September 2010, both much before this question was asked. Both microcontrollers have more than the 2x 8 bit and 1x 16 bit timer/counter specified in the answer. \$\endgroup\$ – Seemingly So Jan 10 '13 at 11:21
  • \$\begingroup\$ Most interactions I've seen so far, have an unambiguous reference to Arduino to mean the like of Duemilanove or Uno i.e. the 328 series based boards. Other boards always have been explicitly qualified by the uP series no. or Mega, Nano, Micro etc. Anyhow, I will humbly accept the correction. In this context, a clarification is better. \$\endgroup\$ – icarus74 Jan 10 '13 at 12:41
1
\$\begingroup\$

Arduino is using all three timers in ATMega328. Timer1 (16 bits) is used for functions like delay() and millis() and for PWM output on pins 5 and 6. The other two timers — Timer0 and Timer2 are used for PWM output on pins 3, 9, 10, 11.

So, there is no Arduino function for timer interrupt. But there is a way. You can use this code to enable timer interrupt on Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

void setup() {
  // Enable Timer2 interrupt.
  TIMSK2 = (0<<OCIE2A) | (1<<TOIE2);
}

void loop() {
  // Your main loop.
}

I wrote this code without testing, so it is possible I made a mistake. In that case, check datasheet, p.156.

If you want to change timer frequency (prescaler), simply change register TCCR2A. For more info look into datasheet page 153. But if you change frequency of timer, you also change frequency of PWM signal on two output pins!

\$\endgroup\$
  • \$\begingroup\$ AFAIK on ATmega328 Timer0 and Timer2 are 8 bit and only Timer1 is 16 bit. \$\endgroup\$ – tuupola Feb 12 '12 at 20:44
  • \$\begingroup\$ Yes, you are right. I made a mistake. Thank you. \$\endgroup\$ – vasco Feb 13 '12 at 15:39
  • \$\begingroup\$ No, this is not correct. It is Timer0, not Timer1, that is used for delay() and millis() and for PWM output on pins 5 and 6. Timer0 is an 8-bit timer. See e.g. Arduino Timers and Interrupts. \$\endgroup\$ – Peter Mortensen Aug 8 '15 at 0:18

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.