| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| et:examples:timer:hardware_delay [2010/02/08 12:25] – mikk.leini | et:examples:timer:hardware_delay [2020/07/20 09:00] (current) – external edit 127.0.0.1 |
|---|
| ====== Raudvaraline viide ====== | <pagebreak> |
| | ====== Riistvaraline viide ====== |
| |
| //Vajalikud teadmised: [HW] [[et:hardware:homelab:controller]], [AVR] [[et:avr:timers]], [LIB] [[et:software:homelab:library:pin]], [LIB] [[et:software:homelab:library:delay]], [LIB] [[et:software:homelab:library:timer]], [PRT] [[et:examples:timer:software_delay]]// | //Vajalikud teadmised: [HW] [[et:hardware:homelab:controller]], [AVR] [[et:avr:timers]], [LIB] [[et:software:homelab:library:pin]], [LIB] [[et:software:homelab:library:delay]], [LIB] [[et:software:homelab:library:timer]], [PRT] [[et:examples:timer:software_delay]]// |
| ===== Teooria ===== | ===== Teooria ===== |
| |
| Tarkvaraline viide pole ainus meetod pausi tekitamiseks. Sama asja saab teha ka taimeriga. Taimer on riistvaraline kindla sagedusega suurenev või vähenev loendur. Loenduri taktsignaali saab enamasti tekitada mikrokontrolleri töötaktist või mingist välisest taktist. Taktsignaali sagedust saab üldjuhul ka läbi jagada, et väiksem taktsagedus saavutada - seda tehakse taktijaguriga, mida inglise keeles nimetatakse kui //prescaler//. Oluline on siinkohal siiski fakt, et fikseeritud taktsagedusega loenduri väärtus on lineaarses sõltuvuses ajast. Aja saab välja arvutada, korrutades loenduri taktisignaali perioodi loenduri väärtusega. | Tarkvaraline viide pole ainus meetod pausi tekitamiseks. Sama asja saab teha ka taimeriga. Taimer on riistvaraline kindla sagedusega suurenev või vähenev loendur. Loenduri taktsignaali saab enamasti tekitada mikrokontrolleri töötaktist või mingist välisest taktist. Taktsignaali sagedust saab üldjuhul ka mingi teguriga jagada väiksem taktsageduse saavutamiseks - seda tehakse taktijaguriga, mida inglise keeles nimetatakse //prescaler//. Oluline on siinkohal siiski fakt, et fikseeritud taktsagedusega loenduri väärtus on lineaarses sõltuvuses ajast. Aja saab välja arvutada, korrutades loenduri taktisignaali perioodi loenduri väärtusega. |
| |
| [{{ :examples:timer:timer_counter.png?300|AVR loenduri väärtuse muutusega kaasnevad sündmused}}] | [{{ :examples:timer:timer_counter.png?300|AVR loenduri väärtuse muutusega kaasnevad sündmused}}] |
| |
| AVR loendurid saab panna loenduri ületäitumisest (inglise keeles //overflow//) või kindla väärtuse saavutamisest (inglise keeles //compare match//) teavitama. Ületäitumine tekib hetkel, kui loendur on omistanud maksimaalse võimaliku väärtuse ja alustab uuesti nullist loendamist. Väärtuse saavutamise kontroll toimub loenduri suurendamise hetkel selle uut väärtust kasutaja poolt määratud väärtusega võrreldes. Sündmuse tekkimise korral seatakse AVR olekuregistrites vastavad bitid automaatselt kõrgeks. | AVR loendurit saab panna teavitama loenduri ületäitumisest (inglise keeles //overflow//) või kindla väärtuse saavutamisest (inglise keeles //compare match//). Ületäitumine tekib hetkel, kui loendur on omistanud maksimaalse võimaliku väärtuse ja alustab uuesti nullist loendamist. Kindla väärtuse saavutamise puhul aga toimub loenduri suurendamise hetkel selle uue väärtuse võrdlemine kasutaja poolt määratud väärtusega. Sündmuse tekkimise korral seatakse AVR olekuregistrites vastavad bitid automaatselt kõrgeks. |
| |
| Selleks, et taimeriga viide tekitada, piisabki vaid loenduri seadistamisest ja olekubiti kõrgeks minemise ootamisest. Erinevalt tarkvaralisest viitest ei sõltu taimerite töö kompilaatorist, mis teeb nende kasutamise töökindlamaks. Samas võib AVR loendurite mitmekesisuse (või ka segasuse) tõttu nende seadistamine üsna tülikas tunduda. Olenevalt mikrokontrolleri taktsignaalist võib ka juhtuda, et see ei jagu täpselt soovitud viite perioodiga ja viide ei ole täpne. | Selleks, et taimeriga viide tekitada, piisabki vaid loenduri seadistamisest ja olekubiti kõrgeks minemise ootamisest. Erinevalt tarkvaralisest viitest ei sõltu taimerite töö kompilaatorist, mis teeb nende kasutamise töökindlamaks. Samas võib AVR loendurite mitmekesisuse (või ka segasuse) tõttu nende seadistamine üsna tülikas tunduda. Olenevalt mikrokontrolleri taktsignaalist võib ka juhtuda, et see ei jagu täpselt soovitud viite perioodiga ja viide ei ole täpne. |
| ===== Praktika ===== | ===== Praktika ===== |
| |
| Allpool olev programmikood on aga taimeril põhinev viitefunktsioon, mida on natuke lihtsustatud. Loendamise põhimõte on sama mis tarkvaralise viite funktsioonilgi - tekitatakse soovitud arv 1 ms pikkuseid viiteid. Viite tekitamiseks on kasutusel ATmega128 8-bitine loendur 0. Eelnevalt on juba välja arvutatud, et 14,7456 Mhz taktsageduse puhul peab loenduri taktsignaal olema vähemalt 64 korda jagatud, et 1 ms jooksul 8-bitine loendur üle ei täituks. See, mis väärtust loendur omama peab, et ületäitumine toimuks 1 ms järel, on esitatud avaldise kujul ja omistatud muutujale //timer_start//. //F_CPU// on makro-keele konstant mis näitab taktsagedust hertsides. Nimetatud taktsageduse puhul peaks loenduri väärtus 25,6 olema, kuid kuna murdarve kasutada ei saa, siis loenduri algväärtuseks saab 26. Siin tekib paraku ka viga viite ajas, kuid see on üsna väike (-1,7 μs). | Allpool olev programmikood on taimeril põhinev viitefunktsioon, mida on natuke lihtsustatud. Loendamise põhimõte on sama, mis tarkvaralise viite funktsioonilgi - tekitatakse soovitud arv 1 ms pikkuseid viiteid. Viite tekitamiseks on kasutusel ATmega128 8-bitine loendur 0. Eelnevalt on juba välja arvutatud, et 14,7456 Mhz taktsageduse puhul peab loenduri taktsignaal olema vähemalt 64-ga jagatud, et 1 ms jooksul 8-bitine loendur üle ei täituks. See, mis väärtust loendur omama peab, et ületäitumine toimuks 1 ms järel, on esitatud avaldise kujul ja omistatud muutujale //timer_start//. //F_CPU// on makro-keele konstant, mis näitab taktsagedust hertsides. Nimetatud taktsageduse puhul peaks loenduri väärtus 25,6 olema, kuid kuna murdarve kasutada ei saa, siis loenduri algväärtuseks saab 26. Siin tekib paraku ka viga viite ajas, kuid see on üsna väike (-1,7 μs). |
| |
| Tsüklis toimub loenduri algväärtustamine ja ületäitumise lipukese nullimine (sellesse 1 kirjutades). Seejärel oodatakse, kuni loendur loendab algväärtusest 256-ni, ehk ületäitumiseni. Ületäitumise hetkel läheb ületäitumise lipuke kõrgeks ja 1 ms viide ongi toimunud. Funktsiooni lõpus taimer peatatakse. | Tsüklis toimub loenduri algväärtustamine ja ületäitumise lipukese nullimine (sellesse 1 kirjutades). Seejärel oodatakse, kuni loendur loendab algväärtusest 256-ni, ehk ületäitumiseni. Ületäitumise hetkel läheb ületäitumise lipuke kõrgeks ja 1 ms viide ongi toimunud. Funktsiooni lõpus taimer peatatakse. |
| <code c> | <code c> |
| // | // |
| // Riistvaraline viide millisekundites | // Riistvaraline viide millisekundites Atmega kontrolleril |
| // | // |
| void hw_delay_ms(unsigned short count) | void hw_delay_ms(unsigned short count) |
| } | } |
| </code> | </code> |
| | |
| | <pagebreak> |
| | |
| | Esitatud viite funktsioon kasutab aga taimerite teeki, mille lähtekood Atmega kontrollerile näeb välja järgmine: |
| | |
| | <code c> |
| | // |
| | // Taimer 0 taktijaguri valiku tüüp |
| | // |
| | typedef enum |
| | { |
| | TIMER0_NO_PRESCALE = 0x01, |
| | TIMER0_PRESCALE_8 = 0x02, |
| | TIMER0_PRESCALE_32 = 0x03, |
| | TIMER0_PRESCALE_64 = 0x04, |
| | TIMER0_PRESCALE_128 = 0x05, |
| | TIMER0_PRESCALE_256 = 0x06, |
| | TIMER0_PRESCALE_1024 = 0x07 |
| | } |
| | timer0_prescale; |
| | |
| | // |
| | // Taimer 0 normaalrežiimi seadistamine |
| | // |
| | inline void timer0_init_normal(timer0_prescale prescale) |
| | { |
| | TCCR0 = prescale & 0x07; |
| | } |
| | |
| | // |
| | // Taimer 0 peatamine |
| | // |
| | inline void timer0_stop() |
| | { |
| | TCCR0 = 0x00; |
| | } |
| | |
| | // |
| | // Taimer 0 loenduri väärtuse määramine |
| | // |
| | inline void timer0_set_value(unsigned char value) |
| | { |
| | TCNT0 = value; |
| | } |
| | |
| | // |
| | // Taimer 0 ületäitumise lipukese nullimine |
| | // |
| | inline void timer0_overflow_flag_clear(void) |
| | { |
| | bit_set(TIFR, TOV0); |
| | } |
| | |
| | // |
| | // Taimer 0 ületäitumise lipukese oleku lugemine |
| | // |
| | inline bool timer0_overflow_flag_is_set(void) |
| | { |
| | return (bit_is_set(TIFR, TOV0) ? true : false); |
| | } |
| | </code> |
| | |
| | <pagebreak> |
| |
| Järgnevalt on toodud samasugune programm nagu tarkvaralise viite näiteski. Lühemal 100 ms poolperioodil LED süüdatakse, pikemal 900 ms poolperioodil kustutatakse. Tulemusena vilgatab LED iga sekundi järel. Paraku pole ka selles näites periood täpselt 1 sekund, sest programmi muude funktsioonide täitmine igas tsüklis võtab samuti aega. Täpseks ajastuseks tuleb kasutada 16-bitist taimerit koos katkestustega. | Järgnevalt on toodud samasugune programm nagu tarkvaralise viite näiteski. Lühemal 100 ms poolperioodil LED süüdatakse, pikemal 900 ms poolperioodil kustutatakse. Tulemusena vilgatab LED iga sekundi järel. Paraku pole ka selles näites periood täpselt 1 sekund, sest programmi muude funktsioonide täitmine igas tsüklis võtab samuti aega. Täpseks ajastuseks tuleb kasutada 16-bitist taimerit koos katkestustega. |
| <code c> | <code c> |
| // | // |
| // Kodulabori raudvaralise viite demonstratsioonprogramm. | // Kodulabori riistvaralise viite demonstratsioonprogramm. |
| // Programm vilgutab ~1 sekundi järel hetkeks LED-i. | // Programm vilgutab ~1 sekundi järel hetkeks LED-i. |
| // | // |
| while (true) | while (true) |
| { | { |
| // LED-i süütamine | // LED-i põlema panek |
| pin_clear(debug_led); | pin_clear(debug_led); |
| | |