Top Banner
Arduino Interrupts Paul MacDougal September 8, 2014
30

Arduino Interrupts Paul MacDougal September 8, 2014.

Dec 21, 2015

Download

Documents

Bennett Miles
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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