30
Arduino Interrupts Paul MacDougal September 8, 2014

Arduino Interrupts Paul MacDougal September 8, 2014

Embed Size (px)

Citation preview

Page 1: Arduino Interrupts Paul MacDougal September 8, 2014

ArduinoInterrupts

Paul MacDougal

September 8, 2014

Page 2: 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.

Page 3: Arduino Interrupts Paul MacDougal September 8, 2014

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)– …

Page 4: Arduino Interrupts Paul MacDougal September 8, 2014

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 …

Page 5: Arduino Interrupts Paul MacDougal September 8, 2014

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();}

Page 6: Arduino Interrupts Paul MacDougal September 8, 2014

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();}

Page 7: Arduino Interrupts Paul MacDougal September 8, 2014

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();}

Page 8: Arduino Interrupts Paul MacDougal September 8, 2014

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++;}

Page 9: Arduino Interrupts Paul MacDougal September 8, 2014

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?

Page 10: Arduino Interrupts Paul MacDougal September 8, 2014

Example 4const byte LED = 13, SW = 2;

volatile unsigned char count = 0;void handleSW () { digitalWrite(LED, digitalRead(SW)); count+

+;}

unsigned char lastCount = -1;void handleOtherStuff() { if (count != lastCount) { Serial.print("Count "); Serial.println(count); lastCount = count; }}

void loop () { handleOtherStuff();}

void setup () { //Start up the serial port Serial.begin(9600); Serial.println(F(“Example4")); pinMode (LED, OUTPUT); pinMode (SW, INPUT_PULLUP); attachInterrupt(INT0, handleSW, CHANGE);}

Page 11: Arduino Interrupts Paul MacDougal September 8, 2014
Page 12: Arduino Interrupts Paul MacDougal September 8, 2014

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 lower1fe: 90 91 11 01 lds r25, 0x0111 ; count upper202: 80 50 subi r24, 0x00204: 91 40 sbci r25, 0x01206: 69 f5 brne .+90

Page 13: Arduino Interrupts Paul MacDougal September 8, 2014

Sharing continued// Disable interrupts and copynoInterrupts();short int myCount = count;interrupts();if (myCount == 256) …

1fa: f8 94 cli1fc: 80 91 10 01 lds r24, 0x0110200: 90 91 11 01 lds r25, 0x0111204: 78 94 sei206: 80 50 subi r24, 0x00208: 91 40 sbci r25, 0x0120a: 69 f5 brne .+90

Page 14: Arduino Interrupts Paul MacDougal September 8, 2014

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

Page 15: Arduino Interrupts Paul MacDougal September 8, 2014

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

Page 16: Arduino Interrupts Paul MacDougal September 8, 2014

Example 5#include <PinChangeInt.h>const byte LED = 13, SW = 5;

volatile unsigned char count = 0;void handleSW () { digitalWrite(LED, digitalRead(SW)); count++;}

unsigned char lastCount = -1;void handleOtherStuff() { if (count != lastCount) { Serial.print("Count "); Serial.println(count); lastCount = count; }}

void loop () { handleOtherStuff();}

void setup () { //Start up the serial port Serial.begin(9600); Serial.println(F(“Example4")); pinMode (LED, OUTPUT); pinMode (SW, INPUT_PULLUP); PCintPort::attachInterrupt(SW,

handleSW, CHANGE);}

Page 17: Arduino Interrupts Paul MacDougal September 8, 2014

What we have learned

• We can monitor any pin and have it generate an interrupt

• Different pins can have different ISRs

Page 18: Arduino Interrupts Paul MacDougal September 8, 2014

Example 6#include <avr/sleep.h>#include <PinChangeInt.h>

void wake() { // ISR sleep_disable(); // first thing after waking from sleep: PCintPort::detachInterrupt(SW); // stop LOW interrupt}

void sleepNow(){ set_sleep_mode(SLEEP_MODE_PWR_DOWN); noInterrupts(); // stop interrupts sleep_enable(); // enables sleep bit in MCUCR PCintPort::attachInterrupt(SW, wake, LOW); interrupts(); // allow interrupts sleep_cpu(); // here the device is put to sleep}

Page 19: Arduino Interrupts Paul MacDougal September 8, 2014

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())

Page 20: Arduino Interrupts Paul MacDougal September 8, 2014

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.

Page 21: Arduino Interrupts Paul MacDougal September 8, 2014

Example 7#include <TimerOne.h>const byte LED = 13;

void handleOtherStuff() { delay(250);}

unsigned int led = LOW;void timerISR(){ digitalWrite(LED, led); led ^= (HIGH^LOW);}

void setup () { pinMode (LED, OUTPUT); Timer1.initialize(); // breaks analogWrite() for digital pins 9 and 10 Timer1.attachInterrupt(timerISR, 500000); // attaches timerISR() as a timer overflow interrupt --

blinks at 1 Hz}

void loop () { handleOtherStuff();}

http://playground.arduino.cc/Code/Timer1http://code.google.com/p/arduino-timerone

Page 22: Arduino Interrupts Paul MacDougal September 8, 2014

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.

Page 23: Arduino Interrupts Paul MacDougal September 8, 2014

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.

Page 24: Arduino Interrupts Paul MacDougal September 8, 2014

Example 8#include <avr/wdt.h>const byte LED = 13;uint8_t led = LOW;ISR (WDT_vect) { wdt_setup(WDTO_500MS); digitalWrite(LED, led); led ^= (HIGH^LOW);}void setup () { // configure the pins pinMode (LED, OUTPUT);

noInterrupts(); wdt_setup(WDTO_500MS); interrupts();}void loop () { delay(250);}

void wdt_setup(uint8_t duration){ // interrupts should be disabled wdt_reset(); // kick the dog WDTCSR = (1<<WDCE) |(1<<WDE) |(1<<WDIF); WDTCSR = (0<< WDE)|(1<<WDIE) |(duration&0x7) |((duration&0x8)<<2);}

Page 25: Arduino Interrupts Paul MacDougal September 8, 2014

Resources

• Interrupts

• http://www.gammon.com.au/forum/?id=11488

• Timers

• http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106

Page 26: Arduino Interrupts Paul MacDougal September 8, 2014

Q/A

• Questions?

Page 27: Arduino Interrupts Paul MacDougal September 8, 2014

Notes

• All examples were compiled using arduino 1.0.5 and run on an Arduino Uno R3

Page 28: Arduino Interrupts Paul MacDougal September 8, 2014

#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__) #error "__AVR_ATmega88PA"#elif defined (__AVR_ATmega16__) #error "__AVR_ATmega16"#elif defined (__AVR_ATmega168__) #error "__AVR_ATmega168"#elif defined (__AVR_ATmega168A__) #error "__AVR_ATmega168A"#elif defined (__AVR_ATmega168P__) #error "__AVR_ATmega168P"#elif defined (__AVR_ATmega32__) #error "__AVR_ATmega32"#elif defined (__AVR_ATmega328__) #error "__AVR_ATmega328"#elif defined (__AVR_ATmega328P__) #error "__AVR_ATmega328P"#elif defined (__AVR_ATmega32U2__) #error "__AVR_ATmega32U2"#elif defined (__AVR_ATmega32U4__) #error "__AVR_ATmega32U4"#elif defined (__AVR_ATmega32U6__) #error "__AVR_ATmega32U6"#elif defined (__AVR_ATmega128__) #error "__AVR_ATmega128"#elif defined (__AVR_ATmega1280__) #error "__AVR_ATmega1280"#elif defined (__AVR_ATmega2560__) #error "__AVR_ATmega2560"#else #error "Unknown processor"#endif

Page 29: Arduino Interrupts Paul MacDougal September 8, 2014

Arduino main()• #include <Arduino.h>

• int main(void)• {• init();

• #if defined(USBCON)• USBDevice.attach();• #endif

• setup();

• for (;;) {• loop();• if (serialEventRun) serialEventRun();• }

• return 0;• }

Page 30: Arduino Interrupts Paul MacDougal September 8, 2014

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 reti