Tajmeri unutar atmega 328 TIMER 1 16 bitni
Tajmeri unutar atmega 328 TIMER 1 -16 - bitni
Što je timer? Timer (točnije Timer/Counter) je komad hardwarea ugrađen u mikrokontroler (i drugi kontroleri i procesori ga imaju). Timer programiramo preko posebnih registara. Npr. konfiguriramo prescaler, njegov mode, waveform generator no o svemu detaljnije uskoro. Kako radimo s Croduinom, odnosno Atmel AVR ATmega 328 mikrokontrolerom i ovdje ćemo se koncentrirati na njega. ATmega 328 ima tri timera: timer 0, timer 1 i timer 2. Timer 0 i timer 2 su 8 bitni timer, timer 1 je 16 bitni. Glavna razilika je rezolucija, 8 bitni je 256 vrijednosti a 16 bitno 65536 za veću rezoluciju.
Svi timeri ovise o satu sustava, on je na Croduinu 16 Mhz. Svi timeri na Arduino firmwareu (bootloaderu) su konfigurirani na 1 k. Hz frekvenciju i svi interrupti su omogućeni. Zamislite da imate brojač koji kada pritisnete gumb se povećava za jedan. Timer/counter radi na istom principu: broji otkucaje sata. Spomenili smo već da je brzina brojanja 16 miliuna otkucaja u sekundi, otprilike 63 ns po otkucaju ili operaciji. 8 bitni timer će tako brojati od 0 -255, a 16 bitni od 065535. Vrijeme potrebno da se counter resetira je 256/16. 000 = 16 us, odnosno 65536/16. 000 = 4 ms za 16 bitni registar. Ne baš praktičan način za zablinkati LEDicu svakih 1 sekundu. Umjesto kontroliranja brzine timer/countera koristiti ćemo nešto se zove prescaler. U nastavku bavimo se registrima zaduženim za timere, a u jednom od njih definirati ćemo i prescaler.
Prescaler definira brzinu određenog timera (timer 0, timer 1 ili timer 2) prema formuli: (brzina timera [Hz]) = (brzina Arduino clocka (16 MHz) [Hz]) / prescaler Prema datasheetu prescalaru su definirane vrijednosti od 1, 8, 64, 256 i 1024. Vidljivo je kako će prescaler 1 inkrementirati clock od 16 Mhz, prescaler 8 2 Mhz, prescaler 64 250 k. Hz i td. Jednostavno rečeno, prescaler postavljen na 1024 će svakih 1024 otkucaja 16 Mhz timer/countera na svoj counter (timer 0, timer 1, timer 2) dodati 1. Najjednostavnije rečeno dok Mujo pojede 1024 čevapa, Haso će 1. Vratimo se timerima. Prvi novi registar koji ćemo spomenuti u ovom tutorialu je OCR - output compare register u koji ćemo spremiti compare match vrijednost. Čini se previše odjednom? Nije, već smo sve ovo spomenuli samo smo im dali službena imena. Ubacimo u formulu gore kako bismo lakše vizualizirali:
Objašnjenje: 16 Mhz - brzina timer/countera clocka Arduina, uvrštavamo kao 16. 000 Hz brzina. timera - s obzirom kako želimo blinkati LEDicu svakih sekundu, uvrštavamo frekvenciju 1 Hz -1 - counter broj od 0 pa uvrštavamo -1 u formulu
Iz tablice vidimo kako je najmanji prescalar koji možemo koristiti 256 i to za 16 bitni timer 1. Razlog? Vrijednost 62499 možemo spremiti u 16 bitni registar timera 1. Za mjerenje countera u frekvenciji 1 Hz(1 sekunda) možemo koristiti i prescaler 1024, međutim točnije je koristiti manji prescaler. U nijednom od ovih slučajeva ne možemo koristiti 8 bitne timer 0 i timer 2. Sada kada smo odabrali timer i prescaler vrijeme je da upoznamo registre koje trebamo postaviti.
Registri TCCR 1 A Timer count control register - 0 b 0000 (normal) TCCR 1 B Timer count control register - 0 b 00000100 (no icr)(256 prescaler) TCCR 1 C Timer count control register - 0 b 0000 (no force) OCR 1 AH output compare register - high byte 0 x. F 4 OCR 1 AL output compare register - low byte 0 x 23 Na ovim registrima postavljamo izračunatu compare match vrijednost, 62499. S obzirom kako postavljamo posebno high i low byte pretvoramo 62499 iz dekadskog u heksadekadski a to je 0 x. F 423. Pa je tako high byte = 0 x. F 4, a low byte 0 x 23. TIMSK 1 timer interrupt mask 0 b 00000010 (output compare u enable - OCIE 1 A) Portovi: DDRB PORTB
void setup() { DDRB = B 00100000; // port. B 5 (pin 13) postavljamo kao output cli(); //onemogucujemo sve interrupte, kako timer intuerrupt ne bi bio prekinut drugim interruptom s većim prioritetom TCCR 1 A = 0 b 0000; TCCR 1 B = 0 b 00000100; TCCR 1 C = 0 b 0000; OCR 1 AH = 0 x. F 4; OCR 1 AL = 0 x 23; TIMSK 1 = 0 b 00000010; sei(); // ponovno omogucujemo interrupte, ukljucujuci i timer interrupte } ISR(TIMER 1_COMPA_vect) { // timer compare interrupt service routine PORTB ^= 0 b 00100000; // XOR operator, ako je upaljena LEDica gasimo je i obratno } void loop() { }
Timer biblioteka Nekoliko je timer biblioteka koje koriste različite funkcije. Odraditi ćemo samo one koje bismo i koristili u primjeru blinkanja LED-ice. Timer 0 Koristi se za funkcije kao delay(), millis() and micros(). delay() - zaustavlja mikrokontroler za zadani broj milisekundi, postoji i funkcija delay. Microseconds() i sl. millis() - funkcija u koju je spremljeno vrijeme od pokretanja mikrokontrolera, ili resetrianja, u milisekundama. Do overflowa može brojati 15 ak dana. micros() - funkcija u koju je spremljeno vrijeme od pokretanja mikrokontrolera, ili resetrianja, u mikrosekundama. Do overflowa može brojati 70 ak minuta.
Primjer vremenske funkcije bez delay(); unsigned long proslo_vrijeme = 0; // generalno koristimo unsigned long za varijable koje spremaju vrijeme void setup() { pin. Mode(13, OUTPUT); } void loop() { unsigned long trenutno_vrijeme = millis(); // spremamo trenutno vrijeme od pokretanja mikrokontrolera if (trenutno_vrijeme - proslo_vrijeme >= 1000) { proslo_vrijeme = trenutno_vrijeme; // spremi kada je poslijednji put blinknula LEDica digital. Write(13, digital. Read(13) ^ 1); // mijenjaj stanje LEDice } }
Zaključak Osim što nam, funkcije koje smo upravo odradili, omogućuju multitasking daju nam i puno bolji uvid u vrijeme odvijanja operacija. Usporedimo li blinkanje LEDice programirane na ovaj način i one Arduino digital. Write() i delay() funkcijama primjetiti ćemo kako nakon određenog vremena dolazi do odstupanja u trenutcima blinkanja. Za što točnije praćenje rada mikrokontrolera i interrupta nužno je supustiti se na niži programski jezik.
- Slides: 16