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.
-
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– clabacchio2012年02月09日 08:06:39 +00:00Commented Feb 9, 2012 at 8:06
-
\$\begingroup\$ This article might help you. engblaze.com/… \$\endgroup\$Seth Archer Brown– Seth Archer Brown2012年02月10日 22:48:32 +00:00Commented Feb 10, 2012 at 22:48
4 Answers 4
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
};
-
\$\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– JRobert2012年02月09日 21:02:40 +00:00Commented Feb 9, 2012 at 21:02
-
\$\begingroup\$ Note that prescales of 32 and 128 are not available for timer0 and timer1 (atleast with atmega328). \$\endgroup\$tuupola– tuupola2012年02月12日 19:50:00 +00:00Commented Feb 12, 2012 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– JRobert2012年02月13日 01:37:14 +00:00Commented Feb 13, 2012 at 1:37
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.
-
\$\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– clabacchio2012年02月09日 08:08:21 +00:00Commented Feb 9, 2012 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– Kortuk2012年02月09日 08:46:03 +00:00Commented Feb 9, 2012 at 8:46
-
\$\begingroup\$ Ah, good :) but at least do the Arduino boards have any timers? \$\endgroup\$clabacchio– clabacchio2012年02月09日 08:48:42 +00:00Commented Feb 9, 2012 at 8:48
-
\$\begingroup\$ Yes, that is how they accomplish things like delay. \$\endgroup\$Kortuk– Kortuk2012年02月09日 09:43:24 +00:00Commented Feb 9, 2012 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– vasco2012年02月09日 14:08:39 +00:00Commented Feb 9, 2012 at 14:08
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.
-
\$\begingroup\$ There are actually several different timer combinations possible depending on which Arduino is being referred to. Answer is misleading. \$\endgroup\$Seemingly So– Seemingly So2013年01月06日 16:04:56 +00:00Commented Jan 6, 2013 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\$bdutta74– bdutta742013年01月10日 07:18:19 +00:00Commented Jan 10, 2013 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– Seemingly So2013年01月10日 11:21:56 +00:00Commented Jan 10, 2013 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\$bdutta74– bdutta742013年01月10日 12:41:56 +00:00Commented Jan 10, 2013 at 12:41
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!
-
\$\begingroup\$ AFAIK on ATmega328
Timer0
andTimer2
are 8 bit and onlyTimer1
is 16 bit. \$\endgroup\$tuupola– tuupola2012年02月12日 20:44:01 +00:00Commented Feb 12, 2012 at 20:44 -
\$\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– Peter Mortensen2015年08月08日 00:18:25 +00:00Commented Aug 8, 2015 at 0:18