1 Bruk av interrupt og Timer i Arduino-program. Når vi skal utføre handlinger som kan inntreffe tilfeldig (ikke forutsigbare hendelser), slik som å håndtere alarmer, at IO ønsker service etc kan vi benytte Polling som et prinsipp eller vi kan mer effektivt benytte Interrupt. Polling. Betyr at CPU en sjekker ved jevne mellomrom om noen trenger å bli betjent. CPU en bruker følgelig masse tid på å spørre enhetene om de trenger oppmerksomhet. Noe som de normalt ikke trenger. -> Bortkastet tid. Polling er enkelt å programmere, da det kun består i å «spørre» enheter om de trenger å bli betjent. Hvis svaret er «ja» kjøres en rutine som betjener enheten. Kan for eksempel gjøre dette med digitalread() i loop()-funksjonen. Interrupt (avbrudd). Betyr at CPU en sjekker ved jevne mellomrom om noen trenger å bli betjent. CPU en sjekker om et avbruddssignal er gitt etter utførelsen av hver instruksjon. Det betyr at det vil gå svært liten tid fra avbrudd er signalert til det blir oppdaget av CPU en. Avbrudd er mer effektiv metode enn polling. CPU en utfører sine oppgaver som normalt, og vil kun avbrytes hvis det kommer et avbruddsignal (interrupt) som varsler en unormal hendelse. Ved interrupt vil normalt kjørende program bli avbrutt for at en avbruddsrutine (ISR Interrupt Service Routine) skal kjøres for å betjene enheten som har signalert avbrudd. Etter at avbruddet er betjent fortsetter CPU en med oppgaven den utførte før avbruddet inntraff. CPU er har en egen avbruddsline (fysisk linje) som brukes for å varsle interrupt (INTR) fra eksterne enheter.
2 Hvordan sette opp Interrupt? Vi benytter funksjonen: attachinterrupt() attachinterrupt() har 3 parametre som vist i følgende kode: attachinterrupt(button_int, changekey, RISING); BUTTON_INT skal være enten 0 eller 1 med Arduino Uno. Dette angir henholdsvis at digital inngang pinne 2 eller 3 skal detektere interrupt. ( Kun 2 innganger til interrupt på Uno.) changekey angir navnet på interrupt-rutina som skal kjøres RISING angir at interrupt skal detekteres på en puls som går fra lav til høy (rising). Vi kan her velge; RISING, FALLING, CHANGE, LOW. CHANGE Interrupt når signalet endrer seg fra lav/høy eller motsatt. LOW Intterupt hvis signaler er lavt. Eksempel 1. const int BUTTON_INT=0; // Interrupt 0 (pin 2 on the Uno) // Set up interrupt attachinterrupt(button_int, tempalarm, RISING); // Interrupt function void tempalarm() kode som håndterer interrupt-kilden Kan ikke inneholde delay() Bør være hurtig, og lite kode.
3 Eksempel 2. 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); void loop() digitalwrite(ledpin, state); // Interrupt-rutina void blink() state =!state;
4 Timer. En Timer benyttes for å tidsstyre kjøring av rutiner. Vi kan sette en Timer-tid fra mikrosekunder opp til minutter/timer. For eksempel kan vi sette opp en rutine til å kjøre fast hvert 100 msek. Vi kan dermed enkelt lage rutiner som går periodisk, for eksempel styring, regulering, sampling. Hvordan sette opp en Timer? Atmega mikrokontroller har 3 timere innebygd. De kan være forholdsvis knotete å sette opp fra bunn av. En enkel måte å sette opp timere på er å benytte et bibliotek som vi finner på nettet. Et enkelt bibliotek er: TimerOne Søk etter TimerOne. Last ned zip-fila og pakk ut innholdet. zip-fila ligger også på hjemmesiden under tidsplan. Pakk ut zip fila. Og du skal se følgende filer: Innholdet i zip-fila.
5 Kopier disse filene til en katalog du kaller TimerOne som må ligge under Libraries under Arduino katalogene som vist på figuren under. Vi kan benytte Timer-funksjonen på følgende vis: #include <TimerOne.h> // Må være med // Initiere og sette opp en timer Timer1.initialize(500000); // ( 0.5 seconds) Timer1.attachInterrupt(changePitch); //Runs "changepitch" on each timer-tick ----------------- Timer1.initialize() angir periodetiden i mikrosekunder. Timer1.attachInterrupt() angir navnet på funksjonen som skal kjøres periodisk
6 Eksempel med timer. /* Enkel test av Timer. Lar timer-rutina styre Led 11. Tid oppgis i mikrosekunder. loop() styrer en frekvens som benyttes av tone() RR mars 2017 Fil: timer1.io */ #include <TimerOne.h> const int LED=11; const int tonepin = 8; int frekvens = 50; void setup() Serial.begin(9600); pinmode(led, OUTPUT); Timer1.initialize(2000000); // set a timer of length 2000000 microseconds (2 second) Timer1.attachInterrupt(blinkLed); //Runs "blinky" on each timer interrupt void loop() tone(tonepin, frekvens,400); frekvens += 50; if (frekvens >= 4000) frekvens = 100; Serial.print("Frekvensen er: "); Serial.println(frekvens); delay(500);
7 //Timer interrupt function void blinkled() static boolean ledonoff = 0; ledonoff =!ledonoff; // Leser inngangen for å sjekke om den er høy eller lav. digitalwrite(led, ledonoff); //Toggle LED State Serial.print("Led er: "); Serial.println(ledOnOff); Eksempel som benytter både interupt og timer. /* Tester både interrupt med bryter (int 0) pinne 2, samt timer som kjører hvert 0.5 sek. RR mars 2015. Fil: fun_with_sound.io */ // Include the TimerOne library #include <TimerOne.h> //Button pins const int BUTTON_INT = 0; //Interrupt 0 (pin 2 on the Uno) const int SPEAKER = 12; //Speaker on pin 12 // Music keys #define NOTE_C 65.. // Volatile variables can change inside interrupts volatile int key = NOTE_C; volatile int octave_multiplier = 1;
8 void setup() //Set up serial Serial.begin(9600); pinmode (SPEAKER, OUTPUT); // Set up interrupt attachinterrupt(button_int, changekey, RISING); //Set up timer interrupt Timer1.initialize(500000); // ( 0.5 seconds) Timer1.attachInterrupt(changePitch); //Runs "changepitch" on each timer interupt // Interrupt function void changekey() kode Endrer tonefrekvensen «C D E F G ---- hver gang vi signaler interrupt. //Timer function. Periodisk. void changepitch() kode - dobler frekvensen ved hver kjøring avspiller med tone() void loop() kode delay(500);
9 Program som skal hinder prelling når en bryter trykkes /* Test av prelling, og styring av Led med PWM. RR mars 2015. Fil: bounce_test_1.io */ const int BLUELED = 9; const int BUTTON = 12; int ledverdi = 0; boolean lastbuttonstate = false; boolean ledon = false; void setup() pinmode(blueled, OUTPUT); pinmode(button, INPUT); void loop() boolean currentbutton = buttononoff(); if ( lastbuttonstate == LOW && currentbutton == HIGH) ledon =!ledon; lastbuttonstate = currentbutton; // Bruke PWM på led bruker analogwrite() // BLUELED kjøres fra 0 -> Max lys. // Hvis bryter er trykket starter den fra 0 igjen. if ( ledon == true) analogwrite(blueled, ledverdi); ledverdi++; if (ledverdi == 255) ledverdi = 0; else ledverdi = 0; analogwrite(blueled, ledverdi); delay(10);
10 // Sjekker tilstand på bryter. Leser 2 ganger. Unngår prelling. boolean buttononoff(void) boolean current = digitalread(button); if ( current!= lastbuttonstate) delay(5); // delay for å unngå prelling på bryter current = digitalread(button); // Leser 1 gang til for å være sikker på verdien return current;