Vajalikud teadmised:
[HW] Kasutajaliidese moodul,
[AVR] Katkestused, [AVR] Loendurid/Taimerid,
[LIB] Sisend-väljundviigud,
[LIB] Taimerid
Käesoleva peatüki eesmärk on demonstreerida katkestuste kasutamist loendurite näitel. Katkestused on mikrokontrolleris esinevatele sündmustele reageerivad programmilõigud. Katkestusi kasutatakse tavaliselt kiireks sündmusele reageerimiseks, kuid neid võib kasutada ka mitme paralleelse protsessi või täpset ajastust nõudvate tegevuste täitmiseks 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. Katkestuse toimumise korral jäetakse peaprogrammi täitmine pooleli ja kontrollitakse katkestuste vektortabelist katkestuse prioriteeti ning seejärel täidetakse juba katkestuse funktsioonis sisalduv programmilõik. Peale katkestuse programmilõigu täitmist jätkatakse peaprogrammi täitmist sealt, kus see enne pooleli jäi.
Järgnev programm näitab, kuidas seadistada loendurit tekitama katkestust. Programmis on kasutusel kaks Kasutajaliidese 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.
Järgnevalt on ära toodud xmega kontrolleril katkestuste kasutamine.
Programmi alguses toimub 16-bitise loendur/taimer E1 seadistamine. Kõigepealt määratakse ära taimeri periood, ehk maksimaalne loendatav väärtus funktsiooniga TC_SetPeriod. Loenduri jaguriks on 1024 ja perioodi väärtuseks 31249, mille tulemusena 32 MHz taktsageduse puhul on loenduri perioodiks täpselt 1 sekund. Seda on lihtne arvutada valemist:
perioodi väärtus = (32000000 Hz / 1024 / 1) - 1 = 31249
Pärast loendur 1 maksimaalse väärtuse saavutamise katkestuse lubamist tuleb katkestuse tekkimine lubada ka globaalselt ehk ü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äisfaili. Katkestuse programmilõik defineeritakse makrofunktsiooniga ISR, mille parameetriks on katkestuse vektori nimi. Nimetatud seadistuste juures on loendur 1 maksimaalse väärtuse saavutamise katkestuse vektoriks TCE1_OVF_vect. Lisaks globaalselt katkestuse lubamisele tuleb üks haaval lubada ka erineva prioriteediga katkestused xmega kontrolleril kasutades PMIC.CTRL registrit.
// Kodulabor III loenduri katkestusega vilkuva LED-i näide #include <homelab/pin.h> #include <homelab/delay.h> #include <homelab/timer.h> #include <avr/interrupt.h> // Katkestus ISR(TCE1_OVF_vect) { // Rohelise LED-i oleku muutmine pin_toggle(led_green); } // Põhiprogramm int main(void) { // LED-i viigu väljundiks seadmine pin_setup_output(led_green); // Taimer E1 perioodi seadistamine // F_CPU/1024/[aeg] - 1 = periood // 32000000 / 1024 / 1 - 1 = 31249 TC_SetPeriod(&TCE1, 31249); // Taimer E1 taktsageduse seadistamine (F_CPU/1024) TC1_ConfigClockSource(&TCE1, TC_CLKSEL_DIV1024_gc); // Taimer E1 seadistamine töötama normaalrežiimis TC1_ConfigWGM(&TCE1, TC_WGMODE_NORMAL_gc); // Kõrge prioriteediga ületäituvuse katkestuse lubamine TC1_SetOverflowIntLevel(&TCE1,TC_OVFINTLVL_HI_gc); // Kõrge prioriteediga katkestuste lubamine PMIC.CTRL |= PMIC_HILVLEN_bm; // Globaalne katkestuste lubamine sei(); // Lõputu tsükkel while (1) { } }
ATmega seeria (antud näites ATmega2561) kontrollerite puhul on katkestuse näide mõnevõrra erinev, kuna taimerid on võrreldes xmega seeria kontrolleritega samuti erinevad.
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
// Kodulabor II loenduri katkestusega vilkuva LED-i näide #include <homelab/pin.h> #include <homelab/delay.h> #include <homelab/timer.h> #include <avr/interrupt.h> // Katkestus ISR(TIMER1_CAPT_vect) { // Rohelise LED-i oleku muutmine pin_toggle(led_green); } // Põhiprogramm int main(void) { // LED-i viigu väljundiks seadmine 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 1 s // 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 (1) { } }
Programmi käivitades on näha, et hoolimata sellest, et põhitsüklis mingeid tegevusi ei ole, toimuvad katkestused ja roheline LED vilgub.