Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Arduino Interrupts General Info Lecturer: Dr. Samuel Kosolapov Arduino Example: Analog Read Serial https://www.arduino.cc/en/Tutorial/AnalogReadSerial This example shows you how to read analog input from the physical world using a potentiometer. A potentiometer is a simple mechanical device that provides a varying amount of resistance when its shaft is turned. By passing voltage through a potentiometer and into an analog input on your board, it is possible to measure the amount of resistance produced by a potentiometer as an analog value. In this example you will monitor the state of your potentiometer after establishing serial communication between your Arduino or Genuino and your computer running the Arduino Software (IDE). 2 Arduino Example: Analog Read Serial. Circuit https://www.arduino.cc/en/Tutorial/AnalogReadSerial Hardware Required: Arduino or Genuino Board 10k ohm Potentiometer Circuit: Connect the three wires from the potentiometer to your board. The first goes from one of the outer pins of the potentiometer to ground. The second goes from the other outer pin of the potentiometer to 5 volts. The third goes from the middle pin of the potentiometer to the analog pin A0. 3 Arduino Example: Analog Read Serial. Code https://www.arduino.cc/en/Tutorial/AnalogReadSerial void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); } Potentiometer shaft is rotated Voltage on A0 is changed // the loop routine runs over and over again forever: void loop() { // read the input on analog pin 0: int sensorValue = analogRead(A0); // print out the value you read: Serial.println(sensorValue); delay(1); // delay in between reads for stability } 4 What is wrong with this code ? void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); } // the loop routine runs over and over again forever: void loop() { // read the input on analog pin 0: int sensorValue = analogRead(A0); // print out the value you read: Serial.println(sensorValue); delay(1); // delay in between reads for stability 1. delay is “blocking function”: While delay is executed microcontroller is 100% busy cannot do anything “useful”: For example: Cannot get data from sensors Cannot control actuators Cannot do calculations 2. analogRead and Serial.println take some time Time of “measurement” is not exact Non “real-time” code } Code with “delay” function is non-professional: for amateurs only or to demonstrate something simple by using short and simple code 5 Multitasking the Arduino: Using millis for timing https://learn.adafruit.com/multi-tasking-the-arduino-part-1/overview Instead of a world-stopping delay, you can check the clock regularly so you know when it is time to act. Timing is “more exact” BUT: processor is still busy to do POLLING (joke about non smart phone) long currentMillis = 0; long previousMillis = 0; long interval = 10; int potValue = 0; void setup() { Serial.begin(9600); } void loop() { currentMillis = millis(); if ( (currentMillis - previousMillis) > interval ) { potValue = analogRead(A0); Serial.println(potValue); previousMillis = currentMillis; } } 6 State Machine: Using millis for multitasking https://learn.adafruit.com/multi-tasking-the-arduino-part-1/overview Variable are used to “remember” state of the “machine” Then, depending on “current” time (measured by millis() ) “machine behaviour can be “changed” Adafruit’ example of “multitasking”: 3 LEDs are blinking independently (different timing) Additionally 2 servo motors operates independently https://learn.adafruit.com/multi-tasking-the-arduino-part-1/using-millis-for-timing This approach is “more professional”, But still, microprocessor is busy for “polling” + Code is not simple to understand 7 Using Interrupts by Multi-tasking the Arduino – Part 2 https://learn.adafruit.com/multi-tasking-the-arduino-part-2 INTERRUPT: An interrupt is a signal that tells the processor to immediately stop what it is doing and handle some high priority processing. That high priority processing is called an Interrupt Handler. An interrupt handler is like any other void function. If you write one and attach it to an interrupt, it will get called whenever that interrupt signal is triggered. When you return from the interrupt handler, the processor goes back to continue what it was doing before. 8 Using Interrupts by Multi-tasking the Arduino – Part 2 https://learn.adafruit.com/multi-tasking-the-arduino-part-2 INTERRUPT: An interrupt is a signal that tells the processor to immediately stop what it is doing and handle some high priority processing. That high priority processing is called an Interrupt Handler. An interrupt handler is like any other void function. If you write one and attach it to an interrupt, it will get called whenever that interrupt signal is triggered. When you return from the interrupt handler, the processor goes back to continue what it was doing before. 9 Sources of Interrupts https://learn.adafruit.com/multi-tasking-the-arduino-part-2 Interrupts can be generated from several sources: Timer interrupts from one of the Arduino timers. External Interrupts from a change in state of one of the external interrupt pins. Pin-change interrupts from a change in state of any one of a group of pins. 10 Timer Interrupts https://learn.adafruit.com/multi-tasking-the-arduino-part-2/timers Don't call us, we'll call you One can use millis() for timing. But in order to make that work, we had to call millis() every time through the loop to see if it was time to do something. It is kind of a waste to be calling millis() more than once a millisecond, only to find out that the time hasn't changed. Wouldn't it be nice if we only had to check once per millisecond? Timers and timer interrupts let us do exactly that. We can set up a timer to interrupt us once per millisecond. The timer will actually call us to let us know it is time to check the clock! 11 Arduino Timers https://learn.adafruit.com/multi-tasking-the-arduino-part-2/timers ; http://www.hobbytronics.co.uk/arduino-timer-interrupts The Arduino Uno has 3 timers: Timer0, Timer1 and Timer2. Timer0 - An 8 bit timer used by Arduino functions delay(), millis() and micros(). Timer1 - A 16 bit timer used by the Servo() library Timer2 - An 8 bit timer used by the Tone() library Timers are simple counters that count at some frequency derived from the 16MHz system clock. You can configure the clock divisor to alter the frequency and various different counting modes. You can also configure them to generate interrupts when the timer reaches a specific count. 12 Arduino Timers. Timer0 https://learn.adafruit.com/multi-tasking-the-arduino-part-2/timers Timer0 is an 8-bit that counts from 0 to 255 and generates an interrupt whenever it overflows. It uses a clock divisor of 64 by default to give us an interrupt rate of 976.5625 Hz (close enough to a 1KHz for our purposes). We won't mess with the freqency of Timer0, because that would break millis()! Arduino timers have a number of configuration registers. These registers can be read or written to using special symbols defined in the Arduino IDE For example, one can use a comparison register known as OCR0A On every tick, the timer counter is compared with the comparison register and when they are equal an interrupt will be generated. 13 Arduino Timers. Timer1. Prescalers http://playground.arduino.cc/Code/Timer1 Timer1's clock speed is defined by setting the prescaler, or divisor. This prescaler can be set to 1, 8, 64, 256 or 1024. Max Period = (Prescale)*(1/Frequency)*(2^17) ime per Tick = (Prescale)*(1/Frequency) Timer1. 16 MHz Prescaler Time per counter tick Max Period 1 0.0625 uS 8.192 mS 8 0.5 uS 65.536 mS 64 4 uS 524.288 mS 256 16 uS 2097.152 mS 1024 64uS 8388.608mS 14 Arduino Timers. Timer1 http://www.hobbytronics.co.uk/arduino-timer-interrupts In this example, Timer1 is used to flash a LED once per second (but without blocking delay function). Obviously, if you are using the Servo Library there will be a conflict, so you should choose another timer. // Variables definition #define ledPin 13 int timer1_counter; 15 Arduino Timers. Timer1. Blinking LED http://www.hobbytronics.co.uk/arduino-timer-interrupts void setup() { pinMode(ledPin, OUTPUT); // initialize timer1 noInterrupts(); TCCR1A = 0; TCCR1B = 0; ISR(TIMER1_OVF_vect) // interrupt service routine { TCNT1 = timer1_counter; // preload timer digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // disable all interrupts // Set timer1_counter to the correct value for our interrupt interval //timer1_counter = 64911; // preload timer 65536-16MHz/256/100Hz //timer1_counter = 64286; // preload timer 65536-16MHz/256/50Hz timer1_counter = 34286; // preload timer 65536-16MHz/256/2Hz TCNT1 = timer1_counter; // preload timer TCCR1B |= (1 << CS12); // 256 prescaler TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt interrupts(); // enable all interrupts } } void loop() { // your program here... } A number of TIMER libraries exists to make timer programming more simple 16 Arduino Timers. Timer1. Analog Read Data from Sensor http://www.hobbytronics.co.uk/arduino-timer-interrupts ISR(TIMER1_OVF_vect) // interrupt service routine { TCNT1 = timer1_counter; // preload timer sensorValue = analogRead(A0); Serial.println(sensorValue); } int timer1_counter; int sensorValue; void setup() { Serial.begin(19200); // initialize timer1 noInterrupts(); TCCR1A = 0; TCCR1B = 0; // disable all interrupts // Set timer1_counter to the correct value for our interrupt interval //timer1_counter = 64911; // preload timer 65536-16MHz/256/100Hz // timer1_counter = 64286; // preload timer 65536-16MHz/256/50Hz // timer1_counter = 34286; // preload timer 65536-16MHz/256/2Hz timer1_counter = 64911; TCNT1 = timer1_counter; // preload timer // TCCR1B |= (1 << CS12); // 256 prescaler // TCCR1B |= (1 << CS11); // 8 prescaler TCCR1B |= (1 << CS10); // no prescaler TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt interrupts(); // enable all interrupts void loop() { // your program here... } For HIGH speed it must be taken into account that Serial speed can be increased and that analogRead takes some time to stabilize. } 17 Arduino UNO. External Interrupt https://www.arduino.cc/en/Reference/AttachInterrupt Arduino UNO: 2 digital pins can be used for External Interrupts INT0 is mapped to Pin2 INT1 is mapped to Pin3 (It is possible to use more pins…but in a more complex way…) Normally you) to translate the ashould use digitalPinToInterrupt(pinctual digital pin to the specific interrupt number. For example, if you connect to pin 3, use digitalPinToInterrupt(3) To use External interrupt Interrupt handler must be created and “associated” with specific pin. This is done by using function attachinterrupt 18 Arduino UNO. External Interrupt MODE https://www.arduino.cc/en/Reference/AttachInterrupt Arduino UNO: 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. const byte ledPin = 13; const byte interruptPin = 2; volatile byte state = LOW; void setup() { pinMode(ledPin, OUTPUT); pinMode(interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE); } Button is connected to Pin2. When button “state” is changed, Interrupt handler “blink” is called See attachInterrupt finction in setup Volatile: because … (Google) void loop() { digitalWrite(ledPin, state); } void blink() { state = !state; } 19 Arduino UNO. What not to do in the ISR (Interrupt Service Routine ==Interrupt Handler) An ISR cannot have any parameters, and they shouldn't return anything. Volatile “status” variable must be used (see “volatile byte state”) : ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be executed after the current one finishes in an order that depends on the priority they have. delay() requires interrupts to work, it will not work if called inside an ISR. millis() relies on interrupts to count, so it will never increment inside an ISR. micros() works initially, but will start behaving erratically after 1-2 ms. delayMicroseconds() does not use any counter, so it will work as normal. Serial data received while in the attached function may be lost. 20