Transcript Interrupts
Arduino Interrupts
Paul MacDougal September 8, 2014
What are they?
• Interrupts are a way for a microcontroller to temporarily stop what it is doing to handle another task.
• The currently executing program is paused, an ISR (interrupt service routine) is executed, and then your program continues, none the wiser.
Kinds of interrupts
• There are 26 different interrupts on an Arduino Uno – 1 Reset – 2 External Interrupt Request 0 (pin D2) – 3 External Interrupt Request 1 (pin D3) – 4 Pin Change Interrupt Request 0 (pins D8 to D13) – 5 Pin Change Interrupt Request 1 (pins A0 to A5) – 6 Pin Change Interrupt Request 2 (pins D0 to D7) – 7 Watchdog Time-out Interrupt – 8 Timer/Counter2 Compare Match A – … – 18 SPI Serial Transfer Complete – 19 USART Rx Complete – … – 25 2-wire Serial Interface (I2C) – …
When would you use one?
• Interrupts can detect brief pulses on input pins. Polling may miss the pulse while you are doing other calculations.
• Interrupts are useful for waking a sleeping processor.
• Interrupts can be generated at a fixed interval for repetitive processing.
• And more …
Example 1 (no interrupts)
const byte LED = 13, SW = 2; void setup() { pinMode(LED, OUTPUT); pinMode(SW, INPUT_PULLUP); } void handleSW() { digitalWrite(LED, digitalRead(SW)); } void loop() { handleSW(); }
Example 2 (no interrupts)
const byte LED = 13, SW = 2; void handleSW() { digitalWrite(LED, digitalRead(SW)); } void handleOtherStuff() { delay(250); } void setup() { pinMode(LED, OUTPUT); pinMode(SW, INPUT_PULLUP); } void loop() { handleSW(); handleOtherStuff(); }
Example 3 (interrupt)
const byte LED = 13, SW = 2; void handleSW() { // ISR digitalWrite(LED, digitalRead(SW)); } void handleOtherStuff() { delay(250); } void setup() { pinMode(LED, OUTPUT); pinMode(SW, INPUT_PULLUP); attachInterrupt(INT0, handleSW, CHANGE); } void loop() { // handleSW(); commented out handleOtherStuff(); }
ISR
• Interrupt Service Routines should be kept short. Interrupts are disabled when the ISR is called, so other interrupts are postponed.
• Do not call millis() or delay() or Serial or … • This one is good: void myISR () { count++; }
What we have learned
• The hardware can call a routine for us based on activity on pin 2 (INT0) • Our loop() code does not need to know what is happening • But, we often want to know what is going on. How do we share that information?
Example 4
const byte LED = 13, SW = 2; volatile unsigned char count = 0; void handleSW () { digitalWrite(LED, digitalRead(SW)); count++; } void setup () { //Start up the serial port unsigned char lastCount = -1; void handleOtherStuff() { Serial.begin(9600); Serial.println(F(“Example4")); if (count != lastCount) { Serial.print("Count "); Serial.println(count); pinMode (LED, OUTPUT); pinMode (SW, INPUT_PULLUP); } lastCount = count; attachInterrupt(INT0, handleSW, CHANGE); } } void loop () { handleOtherStuff(); }
A little more on sharing data
• An interrupt can happen at any time.
• If you share a multi-byte value (e.g. short int) between an ISR and your code, you have to take additional precautions.
volatile short count; if (count == 256) … 1fa: 80 91 10 01 lds r24, 0x0110 ; count lower 1fe: 90 91 11 01 lds r25, 0x0111 ; count upper 202: 80 50 subi r24, 0x00 204: 91 40 sbci r25, 0x01 206: 69 f5 brne .+90
Sharing continued
// Disable interrupts and copy noInterrupts(); short int myCount = count; interrupts(); if (myCount == 256) … 1fa: f8 94 cli 1fc: 80 91 10 01 lds r24, 0x0110 200: 90 91 11 01 lds r25, 0x0111 204: 78 94 sei 206: 80 50 subi r24, 0x00 208: 91 40 sbci r25, 0x01 20a: 69 f5 brne .+90
What we have learned
• Switches bounce and we may be interrupted more often than expected • We must take precautions when sharing data between an ISR and the main code
Pin Change Interrupt
• Pin 2 is INT0 • Pin 3 is INT1 • But, what about pins 0,1,4,5,6,… • Pin Change Interrupts can monitor all pins
Example 5
#include
What we have learned
• We can monitor any pin and have it generate an interrupt • Different pins can have different ISRs
Example 6
#include
Timer Interrupts
• There are three timers on an Uno. Two are 8 bit and one is 16 bit. They can generate an interrupt when they overflow or when they match a set value.
• The frequency at which the timers increment is programmable • Arduino uses the timers for PWM and for timing (delay(), millis(), micros())
Timers
• Timer0 – 8 bit – controls PWM on pins 5 and 6. Also controls millis() • Timer1 – 16 bit – controls PWM on pins 9 and 10.
• Timer2 – 8 bit – controls PWM on pins 11 and 3.
Example 7
#include
What have we learned
• The fundamental Arduino code uses each of the timers.
• We can sacrifice some functionality and use them for our own purposes.
• The timers are very complex (pages 94 165 in the datasheet). They can be used for lots of cool things.
Watchdog Timer
• The watchdog timer is a separate timer.
• A selectable timeout is programmable (15ms, 30ms, 60ms, 120ms, 250ms, 500ms, 1s, 2s, 4s, 8s) Times are approx.
• If the SW does not reset the WDT (kick the dog) within the timeout period, an interrupt or a reset (or both) occur.
Example 8
#include • • Interrupts http://www.gammon.com.au/forum/?id=114 88 • • Timers http://www.avrfreaks.net/index.php?name= PNphpBB2&file=viewtopic&t=50106 • Questions? • All examples were compiled using arduino 1.0.5 and run on an Arduino Uno R3 #if defined(__AVR_ATtiny45__) #error "__AVR_ATtiny45" #elif defined(__AVR_ATtiny84__) #error "__AVR_ATtiny84" #elif defined(__AVR_ATtiny85__) #error "__AVR_ATtiny85" #elif defined (__AVR_ATtiny2313__) #error "__AVR_ATtiny2313" #elif defined (__AVR_ATtiny2313A__) #error "__AVR_ATtiny2313A" #elif defined (__AVR_ATmega48__) #error "__AVR_ATmega48" #elif defined (__AVR_ATmega48A__) #error "__AVR_ATmega48A" #elif defined (__AVR_ATmega48P__) #error "__AVR_ATmega48P" #elif defined (__AVR_ATmega8__) #error "__AVR_ATmega8" #elif defined (__AVR_ATmega8U2__) #error "__AVR_ATmega8U2" #elif defined (__AVR_ATmega88__) #error "__AVR_ATmega88" #elif defined (__AVR_ATmega88A__) #error "__AVR_ATmega88A" #elif defined (__AVR_ATmega88P__) #error "__AVR_ATmega88P" #elif defined (__AVR_ATmega88PA__) • • • • • • • • • • • • • • } #include ISR(INT0_vect) { 2e8: 1f 92 push r1 2ea: 0f 92 push r0 2ec: 0f b6 in r0, 0x3f ; 63 2ee: 0f 92 push r0 2f0: 11 24 eor r1, r1 2f2: 2f 93 push r18 2f4: 3f 93 push r19 2f6: 4f 93 push r20 2f8: 5f 93 push r21 2fa: 6f 93 push r22 2fc: 7f 93 push r23 2fe: 8f 93 push r24 300: 9f 93 push r25 302: af 93 push r26 304: bf 93 push r27 306: ef 93 push r30 308: ff 93 push r31 30a: 80 91 13 01 lds r24, 0x0113 30e: 90 91 14 01 lds r25, 0x0114 312: 89 2b or r24, r25 314: 29 f0 breq .+10 ; 0x320 <__vector_1+0x38> 316: e0 91 13 01 lds r30, 0x0113 31a: f0 91 14 01 lds r31, 0x0114 31e: 09 95 icall 320: ff 91 pop r31 322: ef 91 pop r30 324: bf 91 pop r27 326: af 91 pop r26 328: 9f 91 pop r25 32a: 8f 91 pop r24 32c: 7f 91 pop r23 32e: 6f 91 pop r22 330: 5f 91 pop r21 332: 4f 91 pop r20 334: 3f 91 pop r19 336: 2f 91 pop r18 338: 0f 90 pop r0 33a: 0f be out 0x3f, r0 ; 63 33c: 0f 90 pop r0 33e: 1f 90 pop r1 340: 18 95 retiResources
Q/A
Notes
Arduino main()