47
Arduino interrupts Version 07/11-2017 / Valle Thorø Side 1 af 47 // Ikke helt færdigredigeret!!! Arduino Timer Interrupts. Hvordan får man Arduino til fx at udføre et interrupt og køre en programstump fx nøjagtig 100 gange i sekundet. Det program, der normalt kører på en controller, er normalt en række af sekventielle instruktioner udført efter hinanden i et loop. Den tid, et loop tager, er derfor afhængig af hvor stort programmet er. Derfor er man nødt til at anvende Interrupts, hvis man skal være sikker på timingen. Et interrupt er en event eller hændelse, udløst enten internt fra en tæller / counter, - eller eksternt fra en pin, der ændrer status. Et Interrupt er en programstump, der udløses af en hændelse og kører asynkront, ikke i et loop. Interrupt’et udløses fx af et key-tryk, - eller af en tid gået, - timer-overflow, osv. Interrupts udløses og udføres et vilkårligt sted i et kørende program og uafhængig heraf. Fx kan et program køre og samtidig kan der af en timer udløses et interrupt, der blinker en LED. Det program, der køres når interuptet opstår, kaldes en interrupt service routine (ISR). Altså: Når et Interrupt opstår, afbrydes det kørende program øjeblikkeligt, og interrupt service rutinen, dvs. en subrutine, kaldes. Når en ISR er færdig, vil det kørende program fortsætte hvorfra det blev afbrudt. Typisk er der gjort brug af interrupts allerede i de tidligere opgaver, der er lavet. De er bare gemt !! Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at bruge funktioner som, millis() , micros() og delayMicroseconds(). Disse funktioner gør brug af interrupts ved brug af timere. PWM-funktionen analogWrite() bruger timere, ligesom tone(), noTone() og Servo library gør. Opsætning af et interrupt

Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

  • Upload
    vannga

  • View
    246

  • Download
    2

Embed Size (px)

Citation preview

Page 1: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 1 af 47

// Ikke helt færdigredigeret!!!

Arduino Timer Interrupts.

Hvordan får man Arduino til fx at udføre et interrupt og køre en programstump fx nøjagtig 100

gange i sekundet.

Det program, der normalt kører på en controller, er normalt en række af sekventielle instruktioner

udført efter hinanden i et loop. Den tid, et loop tager, er derfor afhængig af hvor stort programmet

er.

Derfor er man nødt til at anvende Interrupts, hvis man skal være sikker på timingen.

Et interrupt er en event – eller hændelse, udløst enten internt fra en tæller / counter, - eller eksternt

fra en pin, der ændrer status.

Et Interrupt er en programstump, der udløses af en hændelse og kører asynkront, ikke i et loop.

Interrupt’et udløses fx af et key-tryk, - eller af en tid gået, - timer-overflow, osv.

Interrupts udløses – og udføres et vilkårligt sted i et kørende program – og uafhængig heraf.

Fx kan et program køre – og samtidig kan der af en timer udløses et interrupt, der blinker en LED.

Det program, der køres når interuptet opstår, kaldes en interrupt service routine (ISR).

Altså: Når et Interrupt opstår, afbrydes det kørende program øjeblikkeligt, og interrupt service

rutinen, dvs. en subrutine, kaldes.

Når en ISR er færdig, vil det kørende program fortsætte hvorfra det blev afbrudt.

Typisk er der gjort brug af interrupts allerede i de tidligere opgaver, der er lavet. De er bare gemt !!

Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at bruge

funktioner som, millis() , micros() og delayMicroseconds(). Disse funktioner gør brug af interrupts

ved brug af timere.

PWM-funktionen analogWrite() bruger timere, ligesom tone(), noTone() og Servo library gør.

Opsætning af et interrupt

Page 2: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 2 af 47

Før man kan benytte interrupts, skal der noget opsætning til. Ved at sætte forskellige bits i

forskellige special function registre kan man opsætte processoren til at interrupte på forskellige

events.

Interrupts skal altså enables og den tilhørende interrupt maske skal enables, ligesom det skal

bestemmes, hvad processoren skal udføre, når den interruptes.

Interrupt Service Routine (ISR)

Interrupts can generally enabled / disabled with the function interrupts() / noInterrupts(). By default in the Arduino firmware interrupts are enabled. Interrupt masks are enabled / disabled by setting / clearing bits in the Interrupt mask register (TIMSKx).

When an interrupt occurs, a flag in the interrupt flag register (TIFRx) is been set. This interrupt will be automatically cleared when entering the ISR or by manually clearing the bit in the interrupt flag register.

Der findes to generelt forskellige interrupts: Pinudløste, - og timer/counter udløste interrupts.

Fordelen ved brug af interrupts er, at man kan have et Loop-program til fx at update et 7-segment

display, - og så kan interrupts fx udløst hver 100-del sekund opdatere variable, indeholdende 100-

del sekunder, sekunder, minutter osv.

Pin-udløste interrupts.

Kilder til afsnittet:

Se: http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts/

Pinudløste interrupts kan sættes op til at ske ved en ændring på Arduino-pin 2 eller 3, henholdsvis

INT0 & INT1.

Der kan vælges om det signal på pin’en, der udløser interruptet skal være rising, falling edge, eller

pinchange.

Eksterne interrupts kan sættes op ” the arduino way ” – eller man kan selv pille bit!!

Et eksempel, ” the Arduino Way”:

void setup()

{

pinMode(13, OUTPUT); // Pin 13 is output to which an LED is connected

digitalWrite(13, LOW); // Make pin 13 low, switch LED off

pinMode(2, INPUT); // Pin 2 is input to which a switch is connected = INT0

Page 3: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 3 af 47

pinMode(3, INPUT); // Pin 3 is input to which a switch is connected = INT1

attachInterrupt(0, blink1, RISING);

attachInterrupt(1, blink2, RISING);

// attachInterrupt(0, INT0_handler, CHANGE); //

}

void loop() {

/* Nothing to do: the program jumps automatically to Interrupt Service Routine

"blink" in case of a hardware interrupt on Ardiono pin 2 = INT0 */

}

void blink1(){ // Interrupt service routine

digitalWrite(13, HIGH);

}

void blink2(){ // Interrupt service routine

digitalWrite(13, LOW);

}

http://www.geertlangereis.nl/Electronics/Pin_Change_Interrupts/PinChange_en.html

detachInterrupt(0); // stopper interrupt ! detachInterrupt(1);

Arduino-funktionerne attachInterrupt() og detachInterrupt() bruges kun til pin-udløste interrupts.

Opsætningen af eksterne interrupts kan også styres ved at sætte bits i SFR-registre.

De SFR´s der bruges hertil er:

I External Interrupt Control Register

A indstilles måden, man ønsker et

interrupt udløst.

Eks: EICRA = 0b00000011 ;

Et Extern Interrupt skal enables. Det

sker i External Interrupt Mask

Register, kaldet EIMSK

Og når et INTF flag bliver høj,

udløses et interrupt.

Flaget resettes automatisk når

Interrupt Service Rutinen udføres.

Page 4: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 4 af 47

Kilde: https://sites.google.com/site/qeewiki/books/avr-guide/external-interrupts-on-the-atmega328

Her forsøgt vist grafisk – og med eksempler på at sætte bit:

Kodeeksempler:

void setup(void)

{

pinMode(2, INPUT);

pinMode(13, OUTPUT);

digitalWrite(2, HIGH); // Enable pullup resistor

sei(); // Enable global interrupts

EIMSK |= 0b00000001; // Enable external interrupt INT0

EICRA |= 0b00000010; // Trigger INT0 on falling edge

}

void loop(void)

{

Do something

}

//

ISR(EXT_INT0_vect) // Interrupt Service Routine attached to INT0 vector

ISR(EXT_INT0_vect){

}

Extern Interrupt

Mask Register

/ Valle Thorø, Rev: 5/11 2017

Extern Interrupt setup

ISC01

setBit(EICRA,ISC00);setBit(EIMSK,0);

1

Extern Interrupt

Flag Register

EICRA = B00001010;

B1

1 2

0

Extern Sense

Control Register

Flag cleares automatisk

ved Interruptkald

Int0

SREG Bit 7

1

23

ISC00

INT1_VECT() {

IC Pin 4

B2

sei();

// Enable Global Interrupt

1

23

Ext Int 1

1

ISC11

Mux

02

EIMSK

1

23

Mux

Int1setBit(EICRA,0);

01

EIFR

EIMSK = B00000011;

setBit(EIMSK,INT0);

Bit1

Arduino

Pin 3

Bit1

Int1

Global Interrupt

Enable Bit

Int0

B0

Ext Int 0

10

Status Register

12

0

1

23

11

Bit3

setBit(EIMSK,1);

01

Arduino

Pin 2

Variable, der bruges både i ogudenfor en interruptrutine

skal defineres Globale,

"Volatile"

EICRA

11

ISC10

Sei();

asm("Sei");

Cli();

B0

00

IC Pin 5

B0

SetBit(EIFR,0); // Clr Flag

SetBit(EIFR,1);1 2

INT0_VECT() {

Page 5: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 5 af 47

{

digitalWrite(13, !digitalRead(13)); // Toggle LED on pin 13

}

Men det er muligt, at få flere pins til at udføre interrupts. Se http://www.geertlangereis.nl/Electronics/Pin_Change_Interrupts/PinChange_en.html

Arduino Interrupts

int pbIn = 0; // Interrupt 0 is on DIGITAL PIN 2!

int ledOut = 4; // The output LED pin

volatile int state = LOW; // The input state toggle

void setup()

{

// Set up the digital pin 2 to an Interrupt and Pin 4 to an Output

pinMode(ledOut, OUTPUT);

//Attach the interrupt to the input pin and monitor for ANY Change

attachInterrupt(pbIn, stateChange, CHANGE);

}

void loop()

{

//Simulate a long running process or complex task

for (int i = 0; i < 100; i++)

{

// do nothing but waste some time

delay(10);

}

}

void stateChange()

{

state = !state;

digitalWrite(ledOut, state);

}

http://www.dave-auld.net/index.php?option=com_content&view=article&id=107:arduino-interrupts&catid=53:arduino-input-output-basics&Itemid=107

Page 6: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 6 af 47

Timerudløste interrupts

Ved hjælp af Countere kan man opnå, at man kan få et interrupt til at ske med jævne mellemrum.

Fx hvis man ønsker at få opdateret et stopur hver 100-del af et sekund, eller man ønsker at anvende

en uC som frekvensgenerator. Eller fx som cykelcomputer, hvor der skal tælles pulser i en bestemt

tid.

Små perioder kan direkte udløses direkte ved hjælp af en timer. Men på grund af den ret høje

oscillatorfrekvens, kan længere varigheder mellem interrupts opnås ved fx at tælle antal interrupts i

en variabel, og så kun køre det rigtige interrupt-program hver 100. gang. Programmet kunne her fx

aflæse en sensor !!

En Timer/Counter kan arbejde på to forskellige måder, når en tid skal udmåles.

Man kan indstille en startværdi for Counteren, og så få et interrupt ved overflow

Eller man kan tælle fra 0, og så få et interrupt, når tælleren når en bestemt værdi, indstillet i et

register, et Compare-register.

Counter Overflow Counter Compare Match

Timerens startværdi indstilles, og når timeren

giver overflow, kan der udløses et interrupt.

Counteren starter på 00 00h

Der indsættes en værdi i et Compare-register.

Timerens værdi sammenlignes med Compare-

registeret, og ved match resettes timeren, og der

kan udløses et interrupt.

Indbyggede timere

Arduino Uno har 3 timere indbygget, timer0, timer1 og timer2.

Timer 0: 8 bit

Timer 1: 16 bit.

Timer 2: 8 bit

AT Mega 2560 har yderligere timer 3, 4 og 5, som er 16 bit

Timerne kan indstilles til at tælle eksterne pulser, eller der kan tælles på krystallets frekvens.

Prescaler. / Frekvensdeler.

Page 7: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 7 af 47

På Arduinoen sidder der et 16 MHz krystal. Derfor vil Timeren / Counteren køre ret hurtigt, og give

fx overflow for en 16 bit register i løbet af ca. 4 mS.

Men heldigvis er der indbygget mulighed for at vælge at neddele clockfrekvensen gennem en

frekvensdeler, eller som det kaldes en prescaler.

Hver counter ” har sin egen prescaler ”.

Prescaleren styres af nogle

bit i to SFR-registre,

TimerCounterControl-

Register, TCCRnA eller B

Bittene hedder:

CSn0, CSn1 og CSn2, hvor

tallet n er timerens nummer.

CS står for Clock Select bit.

http://courses.cs.washington.edu/courses/csep567/10wi/lectures/Lecture7.pdf

Se fx http://forum.arduino.cc/index.php/topic,27390.0.html

http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/

Udregning af Prescaler-værdi:

For at få affyret et interrupt med en korrekt frekvens, skal man udregne hvor meget man skal dele

krystallets frekvens ned, så timeren ikke når at give overflow før tiden er gået.

Herefter kan en timers startværdi udregnes, eller en Compare-Match-værdi.

Der kan findes hjælp på en række hjemmesider til at vælge den rette Prescaler til et bestemt formål.

Se fx:

Page 8: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 8 af 47

http://www.et06.dk/atmega_timers/

Forklaring af formlen Skal forbedres!

Udregningen sker som flg:

(timer speed (Hz)) = (Arduino clock speed (16MHz)) / prescaler

𝑖𝑛𝑡𝑒𝑟𝑟𝑢𝑝𝑡 𝑓𝑟𝑒𝑘𝑣𝑒𝑛𝑠 = 16 𝑀𝐻𝑧

𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒𝑟 ∙ ((𝐶. 𝑀𝑎𝑡𝑐ℎ 𝑟𝑒𝑔) + 1)

( + 1 fordi det tager 1 clock cycle at resette.

Ligningen her løst for Compare match register, CMR:

𝐶𝑀𝑅 = (16.000.000

𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒𝑟 ∙ 𝑖𝑛𝑡𝑒𝑟𝑟𝑢𝑝𝑡 𝑓𝑟𝑒𝑘𝑣.) − 1

Værdien skal være mindre end 256 hvis timer 0 eller 2 bruges, og mindre end 65.536 for Timer 1

for at det kan lade sig gøre:

Eksempel:

Interrupt vælges i dette eksempel til 10 gange pr. sekund, dvs. hver 1/10

sekund, eller til 10 Hz.

Timer 1 giver overflow ved FFFFh + 1 = 65536d.

Frekvensen på krystallet er 16 MHz. Dvs. på 0,1 sek. kommer 1.600.000 pulser.

Det er nødvendig med en frekvensdeler, en prescaler, fordi der kommer for mange

pulser på 0,1 sekund.

Der skal mindst deles med ( 1.600.000 / 65.536 ) = ca. 24,8

Prescaleren kan indstilles til 1, 8, 64, 256, 1024.

Page 9: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 9 af 47

fx vælges 64

derfor kommer på 1/10 sekund 1.600.000/64 = 25.000 pulser.

Vælges overflow mode, må tællerens startværdi indstilles til:

( FFFF + 1 ) – 25.000 = 40.536

Vælges Output Compare, tælles fra 0000h og til 25.000. Compare registeret skal

derfor indstilles til 25.000.

Clock select and timer frequency

Different clock sources can be selected for each timer independently. To calculate the timer frequency (for

example 2Hz using timer1) you will need:

1. CPU frequency 16Mhz for Arduino

2. maximum timer counter value (256 for 8bit, 65536 for 16bit timer)

3. Divide CPU frequency through the choosen prescaler (16000000 / 256 = 62500)

4. Divide result through the desired frequency (62500 / 2Hz = 31250)

5. Verify the result against the maximum timer counter value (31250 < 65536 success) if fail, choose

bigger prescaler.

Eksempel på opsætning til 1 HZ interrupt:

Interrupt every second (frequency of 1Hz):

compare match register = [16,000,000 / (prescaler * 1) ] -1

with a prescaler of 1024 you get:

compare match register = [16,000,000 / (1024 * 1) ] -1 = 15,624

since 256 < 15,624 < 65,536, you must use timer1 for this interrupt.

Timer setup code is done inside the setup(){} function in an Arduino sketch.

Control registrere til counterne mm.

For at man kan styre timerne er der en del kontrol-registre, hvis bit – eller indhold skal bestemmes.

Hver timer har et antal SFR-registre tilknyttet.

TCCR1A og TCCR1B

Timer/Counter Control Register.

Pre-scaleren konfigureres her.

Består af 2 x 8 bit registre !!

Page 10: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 10 af 47

Hjælp til valg af prescaler til

forskellige interruptfrekvenser,

se fx calculator ovenfor

Prescaler kan vælges til 1, 8,

64, 256, 1024. ( 1024 kan

ikke laves på timer 2 )

Og Bit WGM12 og WGM13

bestemmer mode.

Vi vælger CTC-mode ( timer )

ved at sætte bit WGM12.

TCNTx

Timer/Counter Register.

Indeholder den aktuelle timer

værdi, 16 bit.

TCNT1H og TCNT1L

OCRxx - Output Compare

Register

16 bit register

OCR1AH og OCR1AL

TIMSKx

Timer/Counter Interrupt Mask

Register. To enable/disable

timer interrupts.

Timer_Overflow_

TIFRx - Timer/Counter

Interrupt Flag Register.

Indicates a pending timer

interrupt.

http://courses.cs.washington.edu/courses/csep567/10wi/lectures/Lecture7.pdf http://www.avrbeginners.net/architecture/timers/timers.html

https://arduino-info.wikispaces.com/Timers-Arduino http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

http://www.eng.utah.edu/~cs5789/2010/slides/Interruptsx2.pdf

Med følgende diagram har jeg forsøgt at lave et samlet diagram over en timer og interrupt-

strukturen:

Page 11: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 11 af 47

Tegningen viser de forskellige registre involveret i opsætningen, og der er givet forskellige

eksempler på hvordan man kan manipulere med bittene i registrene:

Her er en kort oversigt over, hvad der skal opsættes:

Hvad skal gøres? Kode-eksempel

Disable global interrupt

Nulstil tæller

Compare værdien skal indstilles

Vælg CTC Mode

Prescaler-værdien skal indstilles

Timer interrupt skal enables

Enabel Global Timer interrupt

cli();

TCNT1 = 0; // Virker på 16 bit.

OCR1A = 15624; // OCR1A = 0x3D08; på hex form;

bitSet(TCCR1B, WGM12); // WGM12 = 3

bitSet(TCCR1B, CS10); // = 00000001

bitSet(TCCR1B, CS12); //TCCR1B er nu 00000101

bitSet(TIMSK1, OCIE1A);

sei(); // CS12=2, CS11=0, CS10=1

Alle registre og register-bit har navne som compileren kender, og den kender deres værdier. Derfor

kan man fx skrive bitSet(TCCR1B, CS12); For definerede værdier: se

bitSet (TCCR1B, WGM12); sætter et bit der vælger Timer Compare mode. Sættes denne ikke, er

der default valgt overflow mode.

12

3

noInterrupts ();

Frekvensdeler

= Prescaler

/ Valle

000 Stop Timer

001 Divide by 1

010 8

011 64

100 256

101 1024

11* Ekstern clock på T1

ISR(TIMER1_OVF_vect)

{

}

Output Compare Vector

Enable Global

TCCR1B

TIMSK1

Timer0 bruges til delay(); millis(); & micros();

Timer1 til servo();

Timer2 til tone();

CS10 = 0

CS11 = 1

CS12 = 2

WGM12 = 3

[ WGMxx = Wave Generation Mode ]

Timer/Counter 1L

Rev: 05/11-2017

TCCR1B |= ( 1 << CS12 ) | ( 1 << CS10 );

Cli();

Clock-pulser,

Ov erf low Vector

Compare match:

Disable

CTC Mode Interrupt

TCNT1L

12

3

ISR(Timer1_COMPA_Vect)

{

}Output Compare Register

bitSet(TCCR1B, CS12);

TIMSK1 |= B00000010;

Fra Pins

// Vælg Prescaler

12

3

ATMEL AVR ATMEGA328

TIMSK1 |= ( 1 << OCIE1A );

TCNT1 = 0;

bitSet(TCCR1B, 3);

TIMSK1-Bit: [xxxx x, OCIE1B, OCIE1A, TOIE1]

Sæt OCF1Abit16 Bit

Compare

Arduino Timer1 Interrupt-Opsætning

Eks: OCR1A = 15624;

16 Bit

TCNT1 = 25324;

OCRnB

TCCR1B |= B00001000;

Definerede

konstanter:

16 Bit

bitSet(TCCR1B, WGM12);

bitSet(TIMSK1, OCIE1A);

Reset Counter

Overflow:

TCCR1A

TCCR1B |= ( 1 << WGM12 );

bitSet(TIMSK1, 0);

interrupts ();

Timer/Counter 1H

[ CSxx = Clock Select bit ]

TCCR1B |= 0x05;

Sei();

Timer/Counter Control Register A/B

Sæt TOV1 Bit

Timer Interrupt Mask register

Output Compare Interrupt

Flag OCF1A og Overflov

flag TOV1 cleares af

hardware ved interrupt kald

Overflow

Bit 0

OCRnC

Interrupt

TCNT1H

OCR1B

f = ( osc / prescale )

bitSet(TCCR1B, CS10);

TIFR1

Oscillator16 MHz

( Clear Timer on

Compare Match )

TCCR1B-Bit[xxxx WGM12, CS12, CS11, CS10 ]

Timer Compare Value

bitSet(TIMSK1, 1);

[CS12, CS11, CS10]

Mode select registre

( Wave Generation Mode )

Compare

Bit 1

Timer 0 & 2 er kun 8 bit

Preload:

Timer/Counter Interrupt

Flag Register

TIMSK1 |= B00000001;

OCR1A

12

3

TCNT1 = 25324;

12

3

Enable Interrupt i TIMSK-reg:

// = 1024

bitSet(TIMSK1, TOIE1);

( Der er også en kanal B & C )

( Kun Kanal A Clearer timeren )

Turn on Compare ( CTC ) Mode

Timer Overflow Bit Flag

// = 1024

Page 12: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 12 af 47

WGM står for Waveform Generation Bit Mode ?

God dok: http://www.eng.utah.edu/~cs5789/2010/slides/Interruptsx2.pdf

*1 Se datablad: http://www.atmel.com/Images/doc8161.pdf

Timerne kan arbejde i et større antal modes, derfor skal man vælge: CTC Mode ( Counter-Timer-

Compare ?? )

Notice how the setups between the three timers differ slightly in the line which turns on CTC mode:

bitSet (TCCR0A, WGM01); //for timer0

bitSet(TCCR1B, WGM12); //for timer1

bitSet(TCCR2A, WGM21); //for timer2

This follows directly from the datasheet of the ATMEL 328/168 Kilde # .1

Bitmanipulation sker med disse instruktioner:

Fra side om C-bitmanipulation. Se : http://tom-itx.dyndns.org:81/~webpage/avr/c_bits/bits_index.php

| bitwise OR

& bitwise AND

~ bitwise NOT

^ bitwise EXLUSIVE OR (XOR)

<< bit LEFT SHIFT

>> bit RIGHT SHIFT

Ved man hvilke bit der skal sættes i et register, kan man gøre det med en af

følgende eksempler:

TCCR1A = 0b10101010;

TCCR1A = 0; // sæt hele TCCR1A register til 0

TCCR1B = 0;

TCCR1B = 0x03;

TCCR2A = B01000011; // her kendes hvilke bits, der skal sættes.

TCCR2B = B00001001;

TCCR2B |= 7; //Clock select. Internal, prescale 1024~64us

bitSet(TCCR1A, WGM01);

TCCR0A = _BV(WGM01); // Mode = CTC

TCCR0B = _BV(CS02) | _BV(CS00); // _BV er en function, der ???

1 Fra: (http://www.instructables.com/id/Arduino-Timer-Interrupts/step2/Structuring-Timer-Interrupts/ )

Datablad: http://www.atmel.com/Images/doc8161.pdf

Page 13: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 13 af 47

Timer Mode select:

Waveform Generation Mode Bit setup:

Timerne kan tillige indstilles til at hav af

forskellige funktioner. Det styres af ”

Waveform generation bits” også i reg.

TCCR1A og TCCR1B.

Det eneste bit der har interesse her er

WGM12, som vælger CTC mode.

http://www.atmel.com/images/atmel-8271-8-bit-avr-microcontroller-atmega48a-48pa-88a-88pa-168a-168pa-328-328p_datasheet_complete.pdf

Interrupt subrutiner

Her er vist, hvordan man skriver en interrupt-subrutine, en Interrupt Service Rutine.

Eks:

ISR(TIMER1_COMPA_vect) // Compare match

{

seconds++;

if (seconds == 10)

{

seconds = 0;

readMySensor(); // Sker hver 10’ende sekund

}

}

Page 14: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 14 af 47

ISR(TIMER1_OVF_vect) // Overflow interrupt service routine

{

TCNT1 = timer1_counter; // preload timer med værdi, fx med 23445

digitalWrite(ledPin, digitalRead(ledPin) ^ 1);

}

void loop()

{

// your program here...

}

Timer Overflow eksempler:

Timer overflow means the timer has reached is limit value. When a timer overflow interrupt occurs,

the timer overflow bit TOVx will be set in the interrupt flag register TIFRx. When the timer

overflow interrupt enable bit TOIEx in the interrupt mask register TIMSKx is set, the timer

overflow interrupt service routine ISR(TIMERx_OVF_vect) will be called.

I denne mode presettes timerne til en startværdi, - og overflow udløser så et interrupt.

Der kan også tilsluttes en ekstern klock-frekvens. Dvs. man kan tælle eksterne pulser.

Men de fleste gange bliver den interne oscillator-frekvens brugt.

/*

* Arduino 101: timer and interrupts

* Timer1 overflow interrupt example

* more infos: http://www.letmakerobots.com/node/28278

* created by RobotFreak

*/

#define ledPin 13

void setup()

{

pinMode(ledPin, OUTPUT);

// initialize timer1

noInterrupts(); // disable all interrupts

TCCR1A = 0;

TCCR1B = 0;

Page 15: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 15 af 47

TCNT1 = 34286; // preload timer 65536-16MHz/256/2Hz

bitSet(TCCR1B, CS12); // 256 prescaler

bitSet(TIMSK1, TOIE1); // enable timer overflow interrupt

interrupts(); // enable all interrupts

}

ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined

function supplied by attachInterrupt

{

TCNT1 = 34286; // preload timer

digitalWrite(ledPin, digitalRead(ledPin) ^ 1);

}

void loop()

{

// your program here...

}

// Se: http://www.hobbytronics.co.uk/arduino-timer-interrupts

#define ledPin 13

int timer1_counter;

void setup()

{

pinMode(ledPin, OUTPUT);

// initialize timer1

noInterrupts(); // disable all interrupts

TCCR1A = 0;

TCCR1B = 0;

// Set timer1_counter to the correct value for our interrupt interval

//timer1_counter = 64886; // 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

bitSet(TCCR1B, CS12); // 256 prescaler

bitSet(TIMSK1, TOIE1); // enable timer overflow interrupt

interrupts(); // enable all interrupts

}

ISR(TIMER1_OVF_vect) // interrupt service routine

{

TCNT1 = timer1_counter; // preload timer

digitalWrite(ledPin, digitalRead(ledPin) ^ 1);

}

Page 16: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 16 af 47

void loop()

{

// your program here...

}

/*

Eksempel på Interrupt ved timer overflow.

Testet!!

Valle / 8/11-2013

*/

#define ledPin 13

int timer1_startvalue;

int sekund = 0;

int minut = 0;

volatile boolean flag = 0;

//boolean flag = 0;

void setup()

{

pinMode(ledPin, OUTPUT);

Serial.begin(9600);

while (!Serial) {

; // wait for serial port to connect. Needed for Leonardo only

}

// initialize timer1

noInterrupts(); // disable all interrupts

TCCR1A = 0;

TCCR1B = 0;

// Set timer1_startvalue to the correct value for our interrupt interval

//timer1_startvalue = 64886; // preload timer 65536-16MHz/256/100Hz

//timer1_startvalue = 64286; // preload timer 65536-16MHz/256/50Hz

//timer1_startvalue = 34286; // preload timer 65536-16MHz/256/2Hz

timer1_startvalue = 3036; // preload timer 65536-16MHz/256/1Hz

TCNT1 = timer1_startvalue; // preload timer

bitSet(TCCR1B, CS12); // 256 prescaler

bitSet(TIMSK1, TOIE1); // enable timer1 overflow interrupt

interrupts(); // enable all interrupts

}

ISR(TIMER1_OVF_vect) // interrupt service routine

{

TCNT1 = timer1_startvalue; // gen-load timer1

digitalWrite(ledPin, digitalRead(ledPin) ^ 1);

sekund++;

flag = HIGH;

Page 17: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 17 af 47

if (sekund > 59) {

sekund = 0;

minut++;

}

}

void loop()

{

while(flag==LOW) { // Wait til change !!

}

Serial.print(minut);

Serial.print(':');

if(sekund<10) Serial.print('0');

Serial.println(sekund);

flag=0;

// delay(1000);

// your program here...

}

// Se: http://www.hobbytronics.co.uk/arduino-timer-interrupts

Output Compare Match eksempler:

When a output compare match interrupt occurs, the OCFxy flag will be set in the interrupt flag

register TIFRx . When the output compare interrupt enable bit OCIExy in the interrupt mask

register TIMSKx is set, the output compare match interrupt service ISR(TIMERx_COMPy_vect)

routine will be called.

Timerne kan udløse et interrupt hver gang, en timer når op til samme værdi, som er gemt i et timer-

match register, - eller hvis de når deres max count-værdi, og giver overflow.

Når en timer når et match,- bliver det resat på det næste klockpuls – og fortsætter så opad igen fra 0

til næste match.

Ved at vælge Compare match værdien, - og vælge klock-frekvensen ( 16 MHz ) sammen med en

frekvensdeler, en prescaler, kan man kontrollere interruptfrekvensen.

Timeren sætter ved overflow en overflow bit som evt. kan tjekkes manuelt af programmet.

ISR-en ( Interrupt Service Routine resetter overflowbit.

/* Arduino 101: timer and interrupts

Timer1 compare match interrupt example

more infos: http://www.letmakerobots.com/node/28278

created by RobotFreak

*/

Page 18: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 18 af 47

#define ledPin 13

void setup()

{

pinMode(ledPin, OUTPUT);

// initialize timer1

noInterrupts(); // disable all interrupts

TCCR1A = 0;

TCCR1B = 0;

TCNT1 = 0;

OCR1A = 31250; // compare match register 16MHz/256/2Hz

bitSet(TCCR1B, WGM12); // CTC mode

bitSet(TCCR1B, CS12); // 256 prescaler

bitSet(TIMSK1, OCIE1A); // enable timer compare interrupt

interrupts(); // enable all interrupts

}

ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine

{

digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // toggle LED pin

}

void loop()

{

// your program here...

}

// Arduino timer CTC interrupt example

#define LEDPIN 2

void setup()

{

pinMode(LEDPIN, OUTPUT);

// initialize Timer1

cli(); // disable global interrupts

TCCR1A = 0; // set entire TCCR1A register to 0

TCCR1B = 0; // same for TCCR1B

OCR1A = 15624; // set compare match register to desired timer count:

bitSet(TCCR1B, WGM12); // turn on CTC mode:

bitSet(TCCR1B, CS10); // Set CS10 and CS12 bits for 1024 prescaler:

bitSet(TCCR1B, CS12);

Page 19: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 19 af 47

bitSet(TIMSK1, OCIE1A); // enable timer compare interrupt:

sei(); // enable global interrupts:

}

void loop()

{

// do some crazy stuff while my LED keeps blinking

}

ISR(TIMER1_COMPA_vect)

{

digitalWrite(LEDPIN, !digitalRead(LEDPIN));

}

Eksempel på, at tælle antal interrupts, for at få noget til at foregå langsommere!

ISR(TIMER1_COMPA_vect)

{

seconds++;

if (seconds == 10)

{

seconds = 0;

readMySensor();

}

}

void setup()

{

//Use timer 5, output A (pin 44) ( Ikke for Uno )

// initialize timer5

noInterrupts(); // disable all interrupts

TCCR5A = 0;

TCCR5B = 0;

TCNT5 = 0;

OCR5A = 833; // compare match register 16MHz/256/75Hz ~75.03Hz

bitSet(TCCR5B, WGM12); // CTC mode

bitSet(TCCR5B, CS12); // 256 prescaler

bitSet(TIMSK5, OCIE5A); // enable timer compare interrupt mask

interrupts(); // enable all interrupts

}

void loop()

{

Page 20: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 20 af 47

}

ISR(TIMER5_COMPA_vect) // timer compare ISR

{

Serial.print(" et eller andet"); //print RTI fire time

}

// Denne interrupt kaldes ved 1kHz

// http://petemills.blogspot.dk/2011/05/real-time-clock-part-1.html

ISR(TIMER1_COMPA_vect)

{

static uint16_t milliseconds = 0; // mS value for timekeeping 1000mS/1S

static uint16_t clock_cal_counter = 0; // counting up the milliseconds to MS_ADJ

const uint16_t MS_ADJ = 35088; // F_CPU / (F_CPU * PPM_ERROR)

const uint16_t MS_IN_SEC = 1000; // 1000mS/1S

milliseconds++;

clock_cal_counter++;

if( milliseconds >= MS_IN_SEC )

{

milliseconds = 0;

ss++; // increment seconds

toggle_led(); // toggle led

if( ss > 59 )

{

mm++; // increment minutes

ss = 0; // reset seconds

}

if( mm > 59 )

{

hh++; // increment hours

mm = 0; // reset minutes

}

if( hh > 23 )

{

// increment day

hh = 0; // reset hours

}

}

Page 21: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 21 af 47

// milliseconds must be less than 999 to avoid missing an adjustment.

// eg if milliseconds were to be 999 and we increment it here to 1000

// the next ISR call will make it 1001 and reset to zero just as if it

// would for 1000 and the adjustment would be effectively canceled out.

if( ( clock_cal_counter >= MS_ADJ ) && ( milliseconds < MS_IN_SEC - 1 ) )

{

milliseconds++;

// it may be that clock_cal_counter is > than MS_ADJ in which case

// I want to count the tick towards the next adjustment

// should always be 1 or 0

clock_cal_counter = clock_cal_counter - MS_ADJ;

}

}

What are "volatile" variables?

Variables shared between ISR functions and normal functions should be declared "volatile". This

tells the compiler that such variables might change at any time, and thus the compiler must reload

the variable whenever you reference it, rather than relying upon a copy it might have in a processor

register.

For example:

volatile boolean flag;

// Interrupt Service Routine (ISR)

void isr ()

{

flag = true;

} // end of isr

void setup ()

{

attachInterrupt (0, isr, CHANGE); // attach interrupt handler

} // end of setup

void loop ()

{

if (flag)

{

// interrupt has occurred

}

} // end of loop

Page 22: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 22 af 47

Vist gentagelser i det følgende:

Flere noter:

(Note that there are two other OCR (OCR1B and OCR1C not used in this example. However they

may be used independent of OCR1A to generate another frequency or other Timer Counter

Functions.

When that value is reached the output toggles provided that the corresponding output pin is set to

output mode. )

Der er flere måder, hvorpå man kan få udløst et interrupt på tid:

Kode til at sætte værdier i kontrolregistre:

I flere Kode-eksempler er der vist en metode til at indstille registre-bits til interrupt-styring ved at

skifte en kode til venstre.

Fx:

TCCR1B |= (1 << CS12); // 256 prescaler , skift et ‘1’-tal så mange pladser til

venstre, som værdien af CS12. |= betyder Bitwise or.)

Det kan fx bruges, hvis man ikke kender placeringen af bittene i timer kontrol-registrene. Men det

kræver til gengæld, at man ved, at bit CSn2 skal sættes.

I eksemplet skiftes et 1-tal til venstre et antal gange, angivet af værdien af CS12. Compileren

kender denne værdi!

Prædefinerede værdier, som compileren kender:

De er defineret i en include-fil:

#define CS00 0

#define CS01 1

#define CS02 2

#define TOIE1 0 Se: http://courses.cs.washington.edu/courses/csep567/10wi/lectures/Lecture7.pdf

Page 23: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 23 af 47

Ved man hvilke bit der skal sættes i et register, kan man gøre det med en af følgende muligheder:

Interrupt subrutine:

En interrupt service rutine definers som følgende:

ISR(Timerx_ COMPA_VECT) {

Do something

}

Eksempel:

Arduino timer compare match interrupts:

Eksempler på opsætning af Prescaler:

void setup(){

cli(); //stop interrupts

//set timer0 interrupt at 2kHz

TCCR0A = 0; // set entire TCCR0A register to 0

TCCR0B = 0; // same for TCCR0B

TCNT0 = 0; //initialize counter value to 0

OCR0A = 124; // set compare match register for 2khz

// increments

// = (16*10^6) / (2000*64) - 1 (must be <256)

bitSet(TCCR0A, WGM01); // turn on CTC mode

bitSet(TCCR0B, CS01);

bitSet(TCCR0B, CS00); // Set CS01 and CS00 bits for 64 presc.

bitSet(TIMSK0, OCIE0A); // enable timer compare interrupt

//set timer1 interrupt at 1Hz

TCCR1A = 0; // set entire TCCR1A register to 0

TCCR1B = 0; // same for TCCR1B

TCNT1 = 0; //initialize counter value to 0

OCR1A = 15624; // set compare match register for 1hz

// increments

// = (16*10^6) / (1*1024) - 1 (must be <65536)

bitSet(TCCR1B, WGM12); // turn on CTC mode

bitSet(TCCR1B, CS12);

bitSet(TCCR1B, CS10); // Set CS10 og CS12 bits for 1024 presc.

bitSet(TIMSK1, OCIE1A); // enable timer compare interrupt

Page 24: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 24 af 47

//set timer2 interrupt at 8kHz

TCCR2A = 0; // set entire TCCR2A register to 0

TCCR2B = 0; // same for TCCR2B

TCNT2 = 0; //initialize counter value to 0

OCR2A = 249; // set compare match register for 8khz

// increments

// = (16*10^6) / (8000*8) - 1 (must be <256)

bitSet(TCCR2A, WGM21); // turn on CTC mode

bitSet(TCCR2B, CS21); // Set CS21 bit for 8 prescaler

bitSet(TIMSK2, OCIE2A); // enable timer compare interrupt

sei(); //allow interrupts

} //end setup

ISR(TIMER0_COMPA_vect){ //change the 0 to 1 for timer1 and 2 for timer2

//interrupt commands here

}

http://www.instructables.com/id/Arduino-Timer-Interrupts/

Interrupts(); noInterrupts();

Eksempel på beskyttelse af tidskritisk kode

volatile unsigned int count;

/* Det er altid tilrådeligt, at erklære variable, der optræder både i en ISR

og i et loop for globale ( Volatile )

Det får compileren til altid at placere variablene i RAM

*/

ISR (TIMER1_OVF_vect)

{

TCNT1 = 34286; // preload timer

count++;

} // end of TIMER1_OVF_vect

void setup ()

{

pinMode (13, OUTPUT);

noInterrupts(); // disable all interrupts

TCCR1A = 0;

TCCR1B = 0;

TCNT1 = 34286; // preload timer 65536-16MHz/256/2Hz

bitSet(TCCR1B, CS12); // 256 prescaler

Page 25: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 25 af 47

bitSet(TIMSK1, TOIE1); // enable timer overflow interrupt

interrupts(); // enable all interrupts

} // end of setup

void loop ()

{

noInterrupts (); // ; Beskyt loop-koden: = cli();

if (count > 4){

digitalWrite(13, digitalRead(13) ^ 1); // Flip pin

count = 0;

}

interrupts (); // Enable interrupt igen = sei();

// end of loop

}

Oversigtstegninger og animationer over timer-opbygning i ATMEGA processoren.

Der findes også andre

skitser over hvordan

interrupt-strukturen sættes

op.

Bemærk, at PWM1x vist

nu hedder WGM1x

http://www.kner.at/home/40.avr/_architektur/ztcpwm.html

Page 26: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 26 af 47

Her er animeret en compare

match.

http://www.kner.at/home/40.avr/_architektur/ztcbint.html

Page 27: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 27 af 47

Og en overflow match.

http://www.kner.at/home/40.avr/_architektur/ztcbint.html

Resten er endnu ikke helt gennemarbejdet, kan betragtes som Bonus Info

TIMSK1. This is the Timer/Counter1 Interrupt Mask Register. Setting the TOIE1 bit tells the timer to

trigger an interrupt when the timer overflows.

TIMSK and TIFR

The Timer Interrupt Mask Register (TIMSK) and Timer Interrupt Flag (TIFR) Register are used to control which interrupts are "valid" by setting their bits in TIMSK and to determine which interrupts are currently pending (TIFR).

Page 28: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 28 af 47

Bit 7 Bit 0

TOIE1 OCIE1A --- --- TICIE1 --- TOIE0 ---

TOIE1: Timer Overflow Interrupt Enable (Timer 1); If this bit is set and if global interrupts are enabled, the micro will jump to the Timer Overflow 1 interrupt vector upon Timer 1 Overflow.

OCIE1A: Output Compare Interrupt Enable 1 A; If set and if global Interrupts are enabled, the micro will jump to the Output Compare A Interrupt vetor upon compare match.

TICIE1: Timer 1 Input Capture Interrupt Enable; If set and if global Interrupts are enabled, the micro will jump to the Input Capture Interrupt vector upon an Input Capture event.

TOIE0: Timer Overflow Interrupt Enable (Timer 0); Same as TOIE1, but for the 8-bit Timer 0.

TCCR1A = 0x00;

// COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 --

PWM11=0,PWM10=0 => PWM Operation disabled, ICNC1=0 => Capture Noise Canceler

disabled -- ICES1=0 => Input Capture Edge Select (not used) -- CTC1=0 => Clear

Timer/Counter 1 on Compare/Match, CS12=0 CS11=1 CS10=1 => Set prescaler to

clock/64

TCCR1B = 0x03;

// 16MHz clock with prescaler means TCNT1 increments every 4uS,

ICIE1=0 => Timer/Counter 1, Input Capture Interrupt Enable -- OCIE1A=0 => Output

Compare A Match Interrupt Enable -- OCIE1B=0 => Output Compare B Match Interrupt

Enable

TOIE1=0 => Timer 1 Overflow Interrupt Enable

TCCR3A register

COM3A1 COM3A0 COM3B1 COM3B0 COM3C1 COM3C0 WGM11 WGM10

TCCR3B register ICNC3 ICES3 – WGM13 WGM12 CS12 CS11 CS10

http://courses.cs.washington.edu/courses/csep567/10wi/lectures/Lecture7.pdf

Page 29: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 29 af 47

based on the AT90S2313.

http://www.avrbeginners.net/architecture/timers/timers.html

16 bit timere er

lidt mere

complex.

Page 30: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 30 af 47

Timer overflow og interrupt udløses :

http://www.avrbeginners.net/architecture/timers/timers.html

Output Compare Mode

The Output Compare mode is used to perform repeated timing. The value in TCNT1 (which is counting up if not stopped by the prescaler select bits) is permanently compared to the value in OCR1A. When these values are equal to each other, the Output Compare Interrupt Flag (OCF in TIFR) is set and an ISR can be called. By setting the CTC1 bit in TCCR1B, the timer can be automatically cleared upon compare match.

http://www.avrbeginners.net/architecture/timers/timers.html

Page 31: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 31 af 47

http://www.nunoalves.com/classes/spring_2012_cpe355/cpe355-02-b.pdf

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

http://www.protostack.com/blog/2010/09/timer-interrupts-on-an-atmega168/ Gode oversigter over register!

http://www.instructables.com/id/Arduino-Timer-Interrupts/

Example- the following sketch sets up and executes 3 timer interrupts: //timer interrupts

//by Amanda Ghassaei

//June 2012

//http://www.instructables.com/id/Arduino-Timer-Interrupts/

/*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

*/

//timer setup for timer0, timer1, and timer2.

//For arduino uno or any board with ATMEL 328/168.. diecimila, duemilanove,

lilypad, nano, mini...

//this code will enable all three arduino timer interrupts.

//timer0 will interrupt at 2kHz

//timer1 will interrupt at 1Hz

//timer2 will interrupt at 8kHz

//storage variables

boolean toggle0 = 0;

boolean toggle1 = 0;

boolean toggle2 = 0;

void setup(){

pinMode(8, OUTPUT); //set pins as outputs

pinMode(9, OUTPUT);

pinMode(13, OUTPUT);

cli(); //stop interrupts

Page 32: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 32 af 47

//set timer0 interrupt at 2kHz

TCCR0A = 0; // set entire TCCR2A register to 0

TCCR0B = 0; // same for TCCR2B

TCNT0 = 0; //initialize counter value to 0

// set compare match register for 2khz

// increments

OCR0A = 124; // = (16*10^6) / (2000*64) - 1 (must be <256)

TCCR0A |= (1 << WGM01); // turn on CTC mode

TCCR0B |= (1 << CS01) | (1 << CS00); // Set CS01 and CS00 bits for 64

// prescaler

TIMSK0 |= (1 << OCIE0A); // enable timer compare interrupt

//set timer1 interrupt at 1Hz

TCCR1A = 0; // set entire TCCR1A register to 0

TCCR1B = 0; // same for TCCR1B

TCNT1 = 0; //initialize counter value to 0

// set compare match register for 1hz

// increments

OCR1A = 15624; // = (16*10^6) / (1*1024) - 1 (must be <65536)

TCCR1B |= (1 << WGM12); // turn on CTC mode

TCCR1B |= (1 << CS12) | (1 << CS10); // Set CS12 and CS10 bits for 1024

//prescaler

TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt

//set timer2 interrupt at 8kHz

TCCR2A = 0; // set entire TCCR2A register to 0

TCCR2B = 0; // same for TCCR2B

TCNT2 = 0; //initialize counter value to 0

// set compare match register for 8khz

// increments

OCR2A = 249; // = (16*10^6) / (8000*8) - 1 (must be <256)

TCCR2A |= (1 << WGM21); // turn on CTC mode

TCCR2B |= (1 << CS21); // Set CS21 bit for 8 prescaler

TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt

sei();//allow interrupts

}//end setup

ISR(TIMER0_COMPA_vect){ //timer0 interrupt 2kHz toggles pin 8

//generates pulse wave of frequency 2kHz/2 =

//1kHz (takes two cycles for full wave- toggle

// high then toggle low)

if (toggle0){

digitalWrite(8,HIGH);

toggle0 = 0;

}

else{

digitalWrite(8,LOW);

toggle0 = 1;

}

}

ISR(TIMER1_COMPA_vect){ //timer1 interrupt 1Hz toggles pin 13 (LED)

Page 33: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 33 af 47

//generates pulse wave of frequency 1Hz/2 =

//0.5kHz (takes two cycles for full wave-

//toggle high then toggle low)

if (toggle1){

digitalWrite(13,HIGH);

toggle1 = 0;

}

else{

digitalWrite(13,LOW);

toggle1 = 1;

}

}

ISR(TIMER2_COMPA_vect){ //timer1 interrupt 8kHz toggles pin 9

//generates pulse wave of frequency 8kHz/2 =

//4kHz (takes two cycles for full wave- toggle

// high then toggle low)

if (toggle2){

digitalWrite(9,HIGH);

toggle2 = 0;

}

else{

digitalWrite(9,LOW);

toggle2 = 1;

}

}

void loop(){

//do other things here

}

The images above show the outputs from these timer interrupts. Fig 1 shows a square wave oscillating between 0 and 5V at 1kHz (timer0 interrupt), fig 2 shows the LED attached to pin 13 turning on for one second then turning off for one second (timer1 interrupt), fig 3 shows a pulse wave oscillating between 0 and 5V at a frequency of 4khz (timer2 interrupt).

Bike Speedometer

In this example I made an arduino bike speedometer. It works by attaching a magnet to the wheel and measuring the amount of time it takes to pass by a magnetic switch mounted on the frame- the time for one complete rotation of the wheel. I set timer 1 to interrupt every ms (frequency of 1kHz) to measure the magnetic switch. If the magnet is passing by the switch, the signal from the switch is high and the variable "time" gets set to zero. If the magnet is not near the switch "time" gets incremented by 1. This way "time" is actually just a measurement of the amount of time in milliseconds that has passed since the magnet last passed by the magnetic switch. This info is used later in the code to calculate rpm and mph of the bike. Here's the bit of code that sets up timer1 for 1kHz interrupts Here's the complete code if you want to take a look: //bike speedometer

//by Amanda Ghassaei 2012

Page 34: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 34 af 47

//http://www.instructables.com/id/Arduino-Timer-Interrupts/

//http://www.instructables.com/id/Arduino-Timer-Interrupts/

/*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

*/

//sample calculations

//tire radius ~ 13.5 inches

//circumference = pi*2*r =~85 inches

//max speed of 35mph =~ 616inches/second

//max rps =~7.25

#define reed A0//pin connected to read switch

//storage variables

float radius = 13.5;// tire radius (in inches)- CHANGE THIS FOR YOUR OWN BIKE

int reedVal;

long time = 0;// time between one full rotation (in ms)

float mph = 0.00;

float circumference;

boolean backlight;

int maxReedCounter = 100;//min time (in ms) of one rotation (for debouncing)

int reedCounter;

void setup(){

reedCounter = maxReedCounter;

circumference = 2*3.14*radius;

pinMode(1,OUTPUT);//tx

pinMode(2,OUTPUT);//backlight switch

pinMode(reed,INPUT);//redd switch

checkBacklight();

Serial.write(12);//clear

// TIMER SETUP- the timer interrupt allows preceise timed measurements of the reed

switch

//for mor info about configuration of arduino timers see

http://arduino.cc/playground/Code/Timer1

cli();//stop interrupts

//set timer1 interrupt at 1kHz

TCCR1A = 0;// set entire TCCR1A register to 0

TCCR1B = 0;// same for TCCR1B

TCNT1 = 0;//initialize counter value to 0;

// set timer count for 1khz increments

OCR1A = 1999;// = (16*10^6) / (1000*8) - 1

// turn on CTC mode

TCCR1B |= (1 << WGM12);

// Set CS11 bit for 8 prescaler

TCCR1B |= (1 << CS11);

// enable timer compare interrupt

TIMSK1 |= (1 << OCIE1A);

sei();//allow interrupts

//END TIMER SETUP

Page 35: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 35 af 47

Serial.begin(9600);

}

void checkBacklight(){

backlight = digitalRead(2);

if (backlight){

Serial.write(17);//turn backlight on

}

else{

Serial.write(18);//turn backlight off

}

}

ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch

reedVal = digitalRead(reed);//get val of A0

if (reedVal){//if reed switch is closed

if (reedCounter == 0){//min time between pulses has passed

mph = (56.8*float(circumference))/float(time);//calculate miles per hour

time = 0;//reset timer

reedCounter = maxReedCounter;//reset reedCounter

}

else{

if (reedCounter > 0){//don't let reedCounter go negative

reedCounter -= 1;//decrement reedCounter

}

}

}

else{//if reed switch is open

if (reedCounter > 0){//don't let reedCounter go negative

reedCounter -= 1;//decrement reedCounter

}

}

if (time > 2000){

mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0

}

else{

time += 1;//increment timer

}

}

void displayMPH(){

Serial.write(12);//clear

Serial.write("Speed =");

Serial.write(13);//start a new line

Serial.print(mph);

Serial.write(" MPH ");

//Serial.write("0.00 MPH ");

}

void loop(){

//print mph once a second

displayMPH();

delay(1000);

checkBacklight();

}

For this project, I used timer2 interrupts to periodically check if there was any incoming serial data, read it, and store it in the matrix "ledData[]". If you take a look at the code you will see that the main loop of

Page 36: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 36 af 47

the sketch is what is actually responsible for using the info in ledData to light up the correct LEDs and checking on the status of the buttons (a function called "shift()"). The interrupt routine is as short as possible- just checking for incoming bytes and storing them appropriately. Here is the setup for timer2: cli();//stop interrupts

//set timer2 interrupt every 128us

TCCR2A = 0;// set entire TCCR2A register to 0

TCCR2B = 0;// same for TCCR2B

TCNT2 = 0;//initialize counter value to 0

// set compare match register for 7.8khz increments

OCR2A = 255;// = (16*10^6) / (7812.5*8) - 1 (must be <256)

// turn on CTC mode

TCCR2A |= (1 << WGM21);

// Set CS21 bit for 8 prescaler

TCCR2B |= (1 << CS21);

// enable timer compare interrupt

TIMSK2 |= (1 << OCIE2A);

sei();//allow interrupts

Here's the complete Arduino sketch: //BUTTON TEST w/ 74HC595 and 74HC165 and serial communication

//by Amanda Ghassaei

//June 2012

//http://www.instructables.com/id/Arduino-Timer-Interrupts/

/*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

*/

//this firmware will send data back and forth with the maxmsp patch "beat slicer"

//pin connections

#define ledLatchPin A1

#define ledClockPin A0

#define ledDataPin A2

#define buttonLatchPin 9

#define buttonClockPin 10

#define buttonDataPin A3

//looping variables

byte i;

byte j;

byte k;

byte ledByte;

//storage for led states, 4 bytes

byte ledData[] = {0, 0, 0, 0};

//storage for buttons, 4 bytes

byte buttonCurrent[] = {0,0,0,0};

byte buttonLast[] = {0,0,0,0};

byte buttonEvent[] = {0,0,0,0};

byte buttonState[] = {0,0,0,0};

//button debounce counter- 16 bytes

byte buttonDebounceCounter[4][4];

Page 37: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 37 af 47

void setup() {

DDRC = 0xF7;//set A0-2 and A4-5 output, A3 input

DDRB = 0xFF;//digital pins 8-13 output

Serial.begin(57600);

cli();//stop interrupts

//set timer2 interrupt every 128us

TCCR2A = 0;// set entire TCCR2A register to 0

TCCR2B = 0;// same for TCCR2B

TCNT2 = 0;//initialize counter value to 0

// set compare match register for 7.8khz increments

OCR2A = 255;// = (16*10^6) / (7812.5*8) - 1 (must be <256)

// turn on CTC mode

TCCR2A |= (1 << WGM21);

// Set CS21 bit for 8 prescaler

TCCR2B |= (1 << CS21);

// enable timer compare interrupt

TIMSK2 |= (1 << OCIE2A);

sei();//allow interrupts

}

// buttonCheck - checks the state of a given button.

//this buttoncheck function is largely copied from the monome 40h firmware by brian

crabtree and joe lake

void buttonCheck(byte row, byte index)

{

if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) && // if the current

physical button state is different from the

((buttonCurrent[row] ^ buttonState[row]) & (1 << index))) { // last physical button

state AND the current debounced state

if (buttonCurrent[row] & (1 << index)) { // if the current

physical button state is depressed

buttonEvent[row] = 1 << index; // queue up a new button event

immediately

buttonState[row] |= (1 << index); // and set the debounced

state to down.

}

else{

buttonDebounceCounter[row][index] = 12;

} // otherwise the button was previously depressed and now

// has been released so we set our debounce counter.

}

else if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) == 0 && // if the

current physical button state is the same as

(buttonCurrent[row] ^ buttonState[row]) & (1 << index)) { // the last physical

button state but the current physical

// button state is different from the current debounce

// state...

if (buttonDebounceCounter[row][index] > 0 && --buttonDebounceCounter[row][index] ==

0) { // if the the debounce counter has

// been decremented to 0 (meaning the

// the button has been up for

// kButtonUpDefaultDebounceCount

// iterations///

buttonEvent[row] = 1 << index; // queue up a button state change event

if (buttonCurrent[row] & (1 << index)){ // and toggle the buttons

Page 38: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 38 af 47

debounce state.

buttonState[row] |= (1 << index);

}

else{

buttonState[row] &= ~(1 << index);

}

}

}

}

void shift(){

for (i=0;i<4;i++){

buttonLast[i] = buttonCurrent[i];

byte dataToSend = (1 << (i+4)) | (15 & ~ledData[i]);

// set latch pin low so the LEDs don't change while sending in bits

digitalWrite(ledLatchPin, LOW);

// shift out the bits of dataToSend

shiftOut(ledDataPin, ledClockPin, LSBFIRST, dataToSend);

//set latch pin high so the LEDs will receive new data

digitalWrite(ledLatchPin, HIGH);

//once one row has been set high, receive data from buttons

//set latch pin high

digitalWrite(buttonLatchPin, HIGH);

//shift in data

buttonCurrent[i] = shiftIn(buttonDataPin, buttonClockPin, LSBFIRST) >> 3;

//latchpin low

digitalWrite(buttonLatchPin, LOW);

for (k=0;k<4;k++){

buttonCheck(i,k);

if (buttonEvent[i]<<k){

if (buttonState[i]&1<<k){

Serial.write(((3-k)<<3)+(i<<1)+1);

}

else{

Serial.write(((3-k)<<3)+(i<<1)+0);

}

buttonEvent[i] &= ~(1<<k);

}

}

}

}

ISR(TIMER2_COMPA_vect) {

do{

if (Serial.available()){

ledByte = Serial.read();//000xxyys

boolean ledstate = ledByte & 1;

byte ledy = (ledByte >> 1) & 3;

byte ledx = (ledByte >> 3) & 3;

if (ledstate){

ledData[ledy] |= 8 >> ledx;

}

else{

ledData[ledy] &= ~ (8 >> ledx);

}

}//end if serial available

}//end do

Page 39: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 39 af 47

while (Serial.available() > 8);

}

void loop() {

shift();//updates leds and receives data from buttons

}

One last thing to note- certain timer setups will actually disable some of the Arduino library functions. Timer0 is used by the functions millis() and delay(), if you manually set up timer0, these functions will not work correctly. Additionally, all three timers underwrite the function analogWrite(). Manually setting up a timer will stop analogWrite() from working. If there is some portion of your code that you don't want interrupted, considering using cli() and sei() to globally disable and enable interrupts. You can read more about this on the Arduino website.

Page 40: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 40 af 47

Stopwatch http://playground.arduino.cc/Code/Stopwatch

A sketch that demonstrates how to do two (or more) things at once by using millis().

/* StopWatch

* Paul Badger 2008

* Demonstrates using millis(), pullup resistors,

* making two things happen at once, printing fractions

*

* Physical setup: momentary switch connected to pin 4, other side connected to ground

* LED with series resistor between pin 13 and ground

*/

#define ledPin 13 // LED connected to digital pin 13

#define buttonPin 4 // button on pin 4

int value = LOW; // previous value of the LED

int buttonState; // variable to store button state

int lastButtonState; // variable to store last button state

int blinking; // condition for blinking - timer is timing

long interval = 100; // blink interval - change to suit

long previousMillis = 0; // variable to store last time LED was updated

long startTime ; // start time for stop watch

long elapsedTime ; // elapsed time for stop watch

int fractional; // variable used to store fractional part of time

void setup()

{

Serial.begin(9600);

pinMode(ledPin, OUTPUT); // sets the digital pin as output

pinMode(buttonPin, INPUT); // not really necessary, pins default to INPUT anyway

digitalWrite(buttonPin, HIGH); // turn on pullup resistors. Wire button so that press shorts

pin to ground.

}

void loop()

{

// check for button press

buttonState = digitalRead(buttonPin); // read the button state and store

if (buttonState == LOW && lastButtonState == HIGH && blinking== false){ // check for a

high to low transition

// if true then found a new button press while clock is not running - start the clock

startTime = millis(); // store the start time

blinking = true; // turn on blinking while timing

delay(5); // short delay to debounce switch

lastButtonState = buttonState; // store buttonState in

lastButtonState, to compare next time

}

else if (buttonState == LOW && lastButtonState == HIGH &&blinking == true){ // check for a

high to low transition

// if true then found a new button press while clock is running - stop the clock and report

elapsedTime = millis() - startTime; // store elapsed time

blinking = false; // turn off blinking, all done timing

lastButtonState = buttonState; // store buttonState in lastButtonState,

to compare next time

// routine to report elapsed time

Serial.print( (int)(elapsedTime / 1000L)); // divide by 1000 to convert to seconds

- then cast to an int to print

Page 41: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 41 af 47

Serial.print("."); // print decimal point

// use modulo operator to get fractional part of time

fractional = (int)(elapsedTime % 1000L);

// pad in leading zeros - wouldn't it be nice if

// Arduino language had a flag for this? :)

if (fractional == 0)

Serial.print("000"); // add three zero's else if (fractional < 10) // if fractional < 10 the 0 is ignored giving a wrong time, so

add the zeros

Serial.print("00"); // add two zeros else if (fractional < 100)

Serial.print("0"); // add one zero

Serial.println(fractional); // print fractional part of time

}

else{

lastButtonState = buttonState; // store buttonState in

lastButtonState, to compare next time

}

// blink routine - blink the LED while timing

// check to see if it's time to blink the LED; that is, the difference

// between the current time and last time we blinked the LED is larger than

// the interval at which we want to blink the LED.

if ( (millis() - previousMillis > interval) ) {

if (blinking == true){

previousMillis = millis(); // remember the last time we blinked

the LED

// if the LED is off turn it on and vice-versa.

if (value == LOW)

value = HIGH;

else

value = LOW;

digitalWrite(ledPin, value);

}

else{

digitalWrite(ledPin, LOW); // turn off LED when not blinking

}

}

}

Brug af milis: cykelcomputer: Interrupt Triggers hver puls fra føler:

To calculate the circumference – use the formula:

circumference = 2πr

where r is the radius of the circle. Now that you have the wheel circumference, this value can be considered as our

‘fixed distance’, and therefore the speed can be calculated by measuring the elapsed time between of a full

rotation.

Page 42: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 42 af 47

Your sensor – once fitted – should act in the same method as a normally-open button that is pushed every

rotation. Our sketch will measure the time elapsed between every pulse from the sensor. To do this, our example

will have the sensor output connected to digital pin 2 – as it will trigger an interrupt to calculate the speed.

(Interrupts? See chapter three). The sketch will otherwise be displaying the speed on a normal I2C-interface

LCD module. The I2C interface is suggested as this requires only 4 wires from the Arduino board to the LCD –

the less wires the better.

Example 37.3

/*

Example 37.3 – Basic speedometer using millis();

http://tronixstuff.wordpress.com/tutorials > chapter 37

John Boxall | CC by-sa-nc

*/

#include "Wire.h" // for I2C bus LCD

#include "LiquidCrystal_I2C.h" // for I2C bus LCD module - http://bit.ly/m7K5wt

LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16

chars and 2 line display

float start, finished;

float elapsed, time;

float circMetric=1.2; // wheel circumference relative to sensor position (in

meters)

float circImperial; // using 1 kilometer = 0.621371192 miles

float speedk, speedm; // holds calculated speed vales in metric and imperial

void setup()

{

attachInterrupt(0, speedCalc, RISING); // interrupt called when sensors sends

digital 2 high (every wheel rotation)

start=millis();

// setup LCD

lcd.init(); // initialize the lcd

lcd.backlight(); // turn on LCD backlight

lcd.clear();

lcd.println(" Wear a helmet! ");

delay(3000);

lcd.clear();

Serial.begin(115200);

circImperial=circMetric*.62137; // convert metric to imperial for MPH

calculations

}

void speedCalc()

{

elapsed=millis()-start;

start=millis();

speedk=(3600*circMetric)/elapsed; // km/h

speedm=(3600*circImperial)/elapsed; // Miles per hour

}

Page 43: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 43 af 47

void loop()

{

lcd.setCursor(0,0);

lcd.print(int(speedk));

lcd.print(" km/h ");

lcd.print(int(speedm));

lcd.print(" MPH ");

lcd.setCursor(0,1);

lcd.print(int(elapsed));

lcd.print(" ms/rev ");

delay(1000); // adjust for personal preference to minimise flicker

}

There isn’t that much going on – every time the wheel completes one revolution the signal from the sensor will go

from low to high – triggering an interrupt which calls the function speedCalc(). This takes a reading of millis() and

then calculates the difference between the current reading and the previous reading – this value becomes the time

to cover the distance (which is the circumference of the wheel relative to the sensor – stored in

float circMetric=1.2;

and is measured in metres). It finally calculates the speed in km/h and MPH. Between interrupts the sketch

displays the updated speed data on the LCD as well as the raw time value for each revolution for curiosity’s sake.

In real life I don’t think anyone would mount an LCD on a bicycle, perhaps an LED display would be more relevant.

In the meanwhile, you can see how this example works in the following short video clip. Instead of a bike wheel

and reed switch/magnet combination, I have connected the square-wave output from a function generator to the

interrupt pin to simulate the pulses from the sensor, so you can get an idea of how it works:

http://letsmakerobots.com/node/28278

1 Reset

2 External Interrupt Request 0 (pin D2) (INT0_vect)

3 External Interrupt Request 1 (pin D3) (INT1_vect)

4 Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect)

5 Pin Change Interrupt Request 1 (pins A0 to A5) (PCINT1_vect)

6 Pin Change Interrupt Request 2 (pins D0 to D7) (PCINT2_vect)

7 Watchdog Time-out Interrupt (WDT_vect)

8 Timer/Counter2 Compare Match A (TIMER2_COMPA_vect)

9 Timer/Counter2 Compare Match B (TIMER2_COMPB_vect)

10 Timer/Counter2 Overflow (TIMER2_OVF_vect)

11 Timer/Counter1 Capture Event (TIMER1_CAPT_vect)

12 Timer/Counter1 Compare Match A (TIMER1_COMPA_vect)

13 Timer/Counter1 Compare Match B (TIMER1_COMPB_vect)

14 Timer/Counter1 Overflow (TIMER1_OVF_vect)

15 Timer/Counter0 Compare Match A (TIMER0_COMPA_vect)

Page 44: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 44 af 47

16 Timer/Counter0 Compare Match B (TIMER0_COMPB_vect)

17 Timer/Counter0 Overflow (TIMER0_OVF_vect)

18 SPI Serial Transfer Complete (SPI_STC_vect)

19 USART Rx Complete (USART_RX_vect)

20 USART, Data Register Empty (USART_UDRE_vect)

21 USART, Tx Complete (USART_TX_vect)

22 ADC Conversion Complete (ADC_vect)

23 EEPROM Ready (EE_READY_vect)

24 Analog Comparator (ANALOG_COMP_vect)

25 2-wire Serial Interface (I2C) (TWI_vect)

26 Store Program Memory Ready (SPM_READY_vect)

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

God og stor samling Tutorials: http://tronixstuff.com/tutorials/

#include <avr/io.h>

#include <avr/interrupt.h>

int ledPin = 8;

volatile int compAval = 10;

void setup() {

Serial.begin(9600);

pinMode(ledPin, OUTPUT);

digitalWrite(ledPin, LOW);

sei(); //Enable interrupts

TCCR2A |= 3; //Fast PWM mode 3.

TCCR2A |= (3 << 6); //fire INT on Compare match

TCNT2 = 0; //initialize Timer2 to 0

OCR2A = compAval; //Set compare A value

TIMSK2 |= (1 << 1); //Enable CompA interrupt

TIMSK2 |= 1; //Enable OVF interrupt

TCCR2B |= 7; //Clock select. Internal, prescale 1024~64us

}

ISR(TIMER2_COMPA_vect)

{

digitalWrite(ledPin, HIGH);

}

ISR(TIMER2_OVF_vect)

{

digitalWrite(ledPin, LOW);

compAval = compAval + 4;

if(compAval > 254)

compAval = 10;

OCR2A = compAval;

}

void loop()

Page 45: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 45 af 47

{

//Serial.println(TCNT2, DEC);

}

http://courses.cs.washington.edu/courses/csep567/10wi/lectures/Lecture6.pdf

Page 46: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 46 af 47

TCCR1B:

Bit 7 Bit 0

ICNC1 ICES1 --- --- CTC1 CS12 CS11 CS10

ICNC1: Input Capture Noise Canceler; If set, the Noise Canceler on the ICP pin is activated. It will trigger the input capture after 4 equal samples. The edge to be triggered on is selected by the ICES1 bit.

ICES1: Input Capture Edge Select;

When cleared, the contents of TCNT1 are transferred to ICR (Input Capture Register) on the falling edge of the ICP pin.

If set, the contents of TCNT1 are transferred on the rising edge of the ICP pin.

CTC1: Clear Timer/Counter 1 on Compare Match; If set, the TCNT1 register is cleared on compare match. Use this bit to create repeated Interrupts after a certain time, e.g. to handle button debouncing or other frequently occuring events. Timer 1 is also used in normal mode, remember to clear this bit when leaving compare match mode if it was set. Otherwise the timer will never overflow and the timing is corrupted.

http://www.let-elektronik.dk/tutorials

en samling links til Jeremy Bloms videos:

Se: http://harperjiangnew.blogspot.dk/2013/05/arduino-using-atmegas-internal.html

http://tom-itx.dyndns.org:81/~webpage/abcminiuser/articles/avr_timers_index.php

CTC mode: http://maxembedded.com/2011/06/28/avr-timers-timer1/

http://www.youtube.com/watch?v=CRJUdf5TTQQ http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/ http://www.protostack.com/blog/2010/09/timer-interrupts-on-an-atmega168/ http://www.instructables.com/id/Arduino-Timer-Interrupts/step2/Structuring-Timer-Interrupts/ http://www.instructables.com/id/Arduino-Timer-Interrupts/ http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/ http://arduino-info.wikispaces.com/Timers-Arduino

Links:

God side om timere: https://sites.google.com/site/qeewiki/books/avr-guide/timer-on-the-atmega8

http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/

Se eksempel på Cykel-computer:

Page 47: Arduino interrupts - vthoroe.dkvthoroe.dk/Elektronik/Arduino/Arduino timer interrupts.pdf · Det er fordi, Arduino´s underlæggende compiler automatisk indbygger mulighed for at

Arduino interrupts Version

07/11-2017

/ Valle Thorø Side 47 af 47

http://www.instructables.com/id/Arduino-Bike-Speedometer/?ALLSTEPS

http://letsmakerobots.com/node/28278

God og stor samling Tutorials: http://tronixstuff.com/tutorials/

http://www.let-elektronik.dk/tutorials

en samling links til Jeremy Bloms videos:

http://harperjiangnew.blogspot.dk/2013/05/arduino-using-atmegas-internal.html

http://tom-itx.dyndns.org:81/~webpage/abcminiuser/articles/avr_timers_index.php

CTC mode: http://maxembedded.com/2011/06/28/avr-timers-timer1/

http://www.youtube.com/watch?v=CRJUdf5TTQQ

Link til datablad: