Timere
Timere i mikrokontroller-sammenheng er i praksis tellere som oppdateres automatisk og kontinuerlig, uavhengig av hva CPU’en holder på med.
ATmega328, som brukes på Arduino UNO, har to 8-bits timere og en 16-bits timer
- 8-bits timere teller fra 0 til 255
- 16-bits timere teller fra 0 til 65535
Det finnes biblioteker som håndterer timer-interrupt, men her skal vi se på hvordan vi bruker registere for å sette verdier direkte, og sette opp pulsbredde-modulering. For å finne ut hvilke registere, og hvilke verdier vi skal bruke, må vi bruke databladet til mikrokontrolleren (ATMega328). Det kan du finne her: https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ProductDocuments/DataSheets/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf
Prinsippet, sammen med en del av de forskjellige registerene vises på flytskjemaet under
Som vi ser på figuren over tar vi utgangspunkt i klokkefrekvensen, som på en Arduino Uno er 16 MHz. Det vil si at hver klokkepuls er 62.5 nanosekunder. Med timere på 8 og 16 bit vil det gi oss en tid på ca 58 mikrosekunder for de to 8 bits timerene og ca 4 millisekunder for 16 bits timeren. Dette er ofte for lite til å gi oss frekvensene vi er ute etter. Derfor har mikrokontrolleren innebygd noe som heter prescaler. Denne kan dele klokkefrekvensen på 8, 64, 256 eller 1024. Det vil si at vi kan gå fra 62,5 nanosekunder til 64 mikrosekunder for hvert "tick" på telleren. Dermed kan vi få periodetider på i overkant av 16 millisekunder for 8 bits og over 4 sekunder for 16 bits timeren.
I databladet refereres det til BOTTOM og TOP:
- Bottom er 0.
- TOP er enten høyeste mulige tellerverdi, eller variabel (satt i software)
Timer 0 og 2
Timer 0 og 2 er 8-bits, og har 6 forskjellige modi:
|
Timer 1
Timer 1 er 16-bits og har 15 modi (modus 13 reservert) |
PWM
PWM står for Pulse Width Modulation (Pulsbredde- eller pulsvidde-modulering på norsk) -styring av et firkantpulstog på en slik måte at de aktive pulslengdene endres, mens periodetiden (og derfor grunnfrekvensen) er konstant ( http://no.wikipedia.org/wiki/PWM ) Forholdet med om av- og på-tid kalles Duty Cycle (kan oversettes direkte med Arbeidssyklus, men det engelske uttrykket brukes) Eksempler på bruksområder:
Duty cycle – forholdet mellom periodetid og pulslengde: |
Oppgaver:
Oppgave 1: Oppgave 2: |
Løsningsforslag:
Oppgave 1: Så lenge vi er inne i ISR'en, vil ikke funksjoner som delay() og millis() fungere, dvs. verdiene blir ikke oppdatert. Vi kan likevel kalle millis() i starten for å registere når knappen er trykt inn. Denne verdien har jeg lagret i variabelen "sisteTrykk" i løsningsforslaget. Neste gang ISR'en kjøres sammenlignes denne med const int interruptPinne = 2; // Definer hvilken pinne som skal brukes for interrupt //Alle variabler som kan endres inne i en ISR må deklareres som "volatile" volatile int interruptTeller = 0; // Variabel for å telle antall ganger interruptet har blitt utløst volatile long sisteTrykk = 0; void setup() { pinMode(interruptPinne, INPUT_PULLUP); // Konfigurer interruptPin som input attachInterrupt(digitalPinToInterrupt(interruptPinne), knapp1Interrupt, FALLING); // Koble interrupt til interruptPin og kall ISR-funksjonen "handleInterrupt" Serial.begin(115200); // Start seriell kommunikasjon med PC } void loop() { Serial.print("Interrupt teller: "); // Skriv antall ganger interruptet har blitt utløst til seriell monitor Serial.println(interruptTeller); delay(1000); } // ISR-funksjonen som blir kalt når interruptet utløses void knapp1Interrupt() { long naa = millis(); if (naa > sisteTrykk + 200) { //Sjekker om det har gått 200 millisekunder siden siste trykk Oppgave 2: Kommer |