This is an old revision of the document!
Vajalikud teadmised: [HW] Controller module, [HW] User Interface Module, [AVR] Interrupts, [AVR] Counters/Timers, [LIB] Pins, [LIB] Delay, [LIB] Timers, [PRT] Software delay
Käesoleva praktilise harjutuse eesmärk on demonstreerida katkestuste kasutamist loendurite näitel. Katkestused on mikrokontrolleris esinevatele sündmustele reageerivad programmilõigud. Katkestusi kasutatakse tavaliselt kiiresti sündmusele reageerimiseks, kuid neid võib kasutada ka mitme paralleelse protsessi täitmiseks, täpselt ajastatud tegevuseks ning voolu säästmiseks. Näiteks on katkestuste abil võimalik panna vilkuma LED, mille vilkumise sagedus ei sõltu sellest, mis programmis parasjagu toimub.
Järgnev programm näitab, kuidas seadistada loendurit katkestust tekitama. Programmis on kasutusel 2 digitaalse mooduli LED-i, millest punase olekut muudetakse perioodiliselt tarkvaralise viitega ja roheline, mille olekut muudetakse katkestuse tekkimisel. Tarkvaralise viitega LED-i vilgutamise kohta on olemas eraldi harjutus ja seda siinkohal selgitatud pole. Põhieesmärk on selgitada loendurite teegi ja katkestuste kasutamist.
Programmi alguses toimub 16-bitise loendur/taimer 1 seadistamine funktsiooniga timer1_init_ctc. Selle funktsiooni abil seatakse loendur CTC (inglise keeles clear timer on compare match) režiimi, kus taimeri maksimaalseks väärtuseks pole mitte 216 - 1, vaid see on valitav. Antud juhul määratakse maksimaalseks väärtuseks ICR1 registri väärtus. Loenduri jaguriks on 1024 ja ICR1 väärtuseks 14400, mille tulemusena 14,7456 Mhz taktsageduse puhul on loenduri perioodiks täpselt 1 sekund. Seda on lihtne arvutada valemist:
f = 14745600 Hz / 1024 / 14400 = 1
Pärast loendur 1 maksimaalse väärtuse saavutamise katkestuse lubamist tuleb katkestuse tekkimine lubada ka globaalselt, ehk siis üle kogu mikrokontrolleri. Globaalseks katkestuste lubamiseks on funktsioon sei ja keelamiseks cli. Nende funktsioonide ja katkestuste programmilõigu defineerimiseks peab programmi kaasama ka avr/interrupt.h päisefaili. Katkestuse programmilõik defineeritakse makrofunktsiooniga ISR, mille parameetriks on katkestuse vektori nimi. Loendur 1 väärtuse saavutamise katkestuse vektori nimi on TIMER1_CAPT_vect.
// // Kodulabori loenduri katkestusega vilkuva LED näide. // Võrdluseks katkestusega vilkuvale LED-ile // töötab paralleelselt ka tarkvaralise viitega vilkuv LED. // #include <homelab/pin.h> #include <homelab/delay.h> #include <homelab/timer.h> #include <avr/interrupt.h> // // LED-ide viikude määramine // pin led_red = PIN(C, 5); pin led_green = PIN(C, 3); // // Katkestus // ISR(TIMER1_CAPT_vect) { // Rohelise LED oleku muutmine pin_toggle(led_green); } // // Põhiprogramm // int main(void) { // LED-ide viikude väljundiks seadmine pin_setup_output(led_red); pin_setup_output(led_green); // Taimeri seadistamine CTC režiimi timer1_init_ctc( TIMER1_PRESCALE_1024, TIMER1_CTC_TOP_ICR); // Taimeri maksimaalne väärtus 14400 mis // teeb perioodi pikkuseks 1s // Valem: 14,7456Mhz / 1024 = 14400 timer1_set_input_capture_value(14400); // Väärtuse saavutamise katkestuse lubamine timer1_input_capture_interrupt_enable(true); // Globaalne katkestuste lubamine sei(); // Lõputu tsükkel while (true) { // Tarkvaraline paus 1000 millisekundit sw_delay_ms(1000); // Punase LED oleku muutmine pin_toggle(led_red); } }
Programmi käivitades on näha, et hoolimata sellest, mida mikrokontroller põhiprogrammis teeb, toimuvad katkestused ja roheline LED vilgub.
Kui programmil lasta töötada mõni minut, tuleb välja oluline aspekt, mida tarkvaralise viite harjutuses nii lihtsalt näha polnud. Kuigi punast LEDi vilgutavas tsüklis olev viide on 1000 ms, siis tegelik aeg, mis kulub iga tsükli täitmiseks, on natukese suurem. Põhjus on selles, et ka LED-i oleku muutmine, viite funktsiooni väljakutsumine ja tsükli täitmine võtavad protsessoril mõned taktid täitmise aega. Tulemusena jääb punase LED-i vilkumine rohelise LED-i vilkumisest pidevalt maha. Just sel põhjusel ei ole soovitatav ka kellaaja loendureid ja muid täpselt ajastatud tegevusi teha viitega, vaid loenduri katkestustega.