====== Perioodiline katkestus ======
//Vajalikud teadmised:
[HW] [[et:hardware:homelab:digi]],
[AVR] [[et:avr:interrupts]], [AVR] [[et:avr:timers]], \\
[LIB] [[et:software:homelab:library:pin]],
[LIB] [[et:software:homelab:library:timer]]//
===== Teooria =====
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.
[{{ :examples:interrupt:katkestus_sekeem.png?500 |Katkestuse täitmise järjekord}}]
===== Praktika =====
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
#include
#include
#include
// 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
#include
#include
#include
// 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.