Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
et:examples:timer:delay [2014/09/30 07:23] raivo.sellet:examples:timer:delay [2020/07/20 09:00] (current) – external edit 127.0.0.1
Line 1: Line 1:
-~~PB~~ 
 ====== Viide ====== ====== Viide ======
  
-//Vajalikud teadmised: [HW] [[et:hardware:homelab:controller]], [AVR] [[et:avr:architecture]], [LIB] [[et:software:homelab:library:pin]], [LIB] [[et:software:homelab:library: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]]//
  
 ===== Teooria ===== ===== Teooria =====
Line 8: Line 10:
 Tihti on mikrokontrollerite programmis vaja tekitada viiteid, et tegevusi ajastada või nende lõppu oodata. Üks idee poolest lihtsamaid meetodeid mikrokontrolleri töös paus tekitada on selle protsessor mingi muu tegevusega üle koormata - näiteks panna see lugema suuri arve. Protsessori taktsagedusest saab välja arvutada, mitmeni see arve loendama peaks, et kindlat ajalist viidet tekitada. Mingi arvu loendamine nullist protsessori taktsageduse väärtuseni hertsides tekitaks teoreetiliselt viite üks sekund. Praktikas see erinevatel põhjustel päris nii lihtne ei ole. Tihti on mikrokontrollerite programmis vaja tekitada viiteid, et tegevusi ajastada või nende lõppu oodata. Üks idee poolest lihtsamaid meetodeid mikrokontrolleri töös paus tekitada on selle protsessor mingi muu tegevusega üle koormata - näiteks panna see lugema suuri arve. Protsessori taktsagedusest saab välja arvutada, mitmeni see arve loendama peaks, et kindlat ajalist viidet tekitada. Mingi arvu loendamine nullist protsessori taktsageduse väärtuseni hertsides tekitaks teoreetiliselt viite üks sekund. Praktikas see erinevatel põhjustel päris nii lihtne ei ole.
  
-Kui mikrokontrolleri protsessor arvutab arvudega, mille kahendkuju on sama lai kui selle sisemine siin (AVR puhul 8-bitti), siis protsessoritel võtab üks aritmeetiline tehe, näiteks arvu liitmine ühega, aega 1 protsessori töötakt. Selleks, et arvutada tuhandete või miljonitega, peab arv olema 16- või 32-bitine ja nende arvutamiseks kulub 8-bitistel protsessoritel rohkem kui 1 töötakt. Niisiis, suurte arvude puhul peab tundma protsessori sisemust - täpsemalt selle käsustikku. +Kui mikrokontrolleri protsessor arvutab arvudega, mille kahendkuju on sama lai kui selle sisemine siin (AVR puhul 8-bitti), siis protsessoritel võtab üks aritmeetiline tehe, näiteks arvu liitmine ühega, aega 1 protsessori töötakt. Selleks, et arvutada tuhandete või miljonitega, peab arv olema 16- või 32-bitine ja nende arvutamiseks kulub 8-bitistel protsessoritel rohkem kui 1 töötakt. Niisiis, suurte arvude puhul peab tundma protsessori sisemust - täpsemalt selle käsustikku. Kuna kõrgtaseme keeles (näiteks C-keeles) programmeerides ei kirjutata programmi otse käsustiku baasil, peab tarkvaralise viite tekitamiseks tundma ka kompilaatorit, mis programmi masinkoodi teisendab. Just sellest sõltub, mitu instruktsiooni (ja sellest tulenevalt mitu takti) kulub aritmeetilisteks arvutusteks. Keerukust lisab veel asjaolu, et kompilaator võib programmi masinkoodi teisendada mitut moodi - näiteks tehes masinkoodi võimalikult mälusäästlikuks või võimalikult kiiresti täidetavaks. Neid kompilaatori tegevusi nimetatakse optimeerimiseks. Erinevate optimeerimise režiimidega tulevad ka tarkvaralise viite masinkood ja selle ajaline kestus erinevad.
- +
-Kuna kõrgtaseme keeles (näiteks C-keeles) programmeerides ei kirjutata programmi otse käsustiku baasil, peab tarkvaralise viite tekitamiseks tundma ka kompilaatorit, mis programmi masinkoodi teisendab. Just sellest sõltub, mitu instruktsiooni (ja sellest tulenevalt mitu takti) kulub aritmeetilisteks arvutusteks. Keerukust lisab veel asjaolu, et kompilaator võib programmi masinkoodi teisendada mitut moodi - näiteks tehes masinkoodi võimalikult mälusäästlikuks või võimalikult kiiresti täidetavaks. Neid kompilaatori tegevusi nimetatakse optimeerimiseks. Erinevate optimeerimise režiimidega tulevad ka tarkvaralise viite masinkood ja selle ajaline kestus erinevad.+
  
 ===== Praktika ====== ===== Praktika ======
Line 18: Line 18:
 <code c> <code c>
 unsigned char x; unsigned char x;
- 
 // Tsükkel seni kuni x on 100 // Tsükkel seni kuni x on 100
 for (x = 0; x < 100; x++) for (x = 0; x < 100; x++)
Line 43: Line 42:
 Näites tekitatud viide on mikrosekundites ja kasutatav muutuja on 8-bitine, seega on ka masinkood üsna lihtne. Selleks, et tekitada pausi millisekundites, on vaja loendada palju suuremaid arve ja siis läheb ka masinkood pikemaks. Võib kasutada ka üksteise sees töötavaid tsükleid, kuid selle meetodi puhul pole kogu viide lineaarses sõltuvuses tsüklite arvust, sest iga tsükli tasemega tekivad pisikesed lisaviited. Näites tekitatud viide on mikrosekundites ja kasutatav muutuja on 8-bitine, seega on ka masinkood üsna lihtne. Selleks, et tekitada pausi millisekundites, on vaja loendada palju suuremaid arve ja siis läheb ka masinkood pikemaks. Võib kasutada ka üksteise sees töötavaid tsükleid, kuid selle meetodi puhul pole kogu viide lineaarses sõltuvuses tsüklite arvust, sest iga tsükli tasemega tekivad pisikesed lisaviited.
  
-Käesoleva harjutuse eesmärk ei ole siiski masinkoodi tasandil täpset tarkvaralist viidet tekitada, sest see on üsna peen töö ja pealegi on viite tekitamiseks avr-libc ja Kodulabori teegis juba funktsioonid olemas. Need kasutatakse ka järgmistes näidetes.+Käesoleva teooriaosa eesmärk ei ole siiski masinkoodi tasandil täpset tarkvaralist viidet tekitada, sest see on üsna peen töö ja pealegi on viite tekitamiseks avr-libc ja Kodulabori teegis juba funktsioonid olemas. Need kasutatakse ka järgmistes näidetes.
  
 Tarkvaralise viite puhul on aga oluline teada, et hoolimata oma põhimõttelisest lihtsusest on see äärmiselt ebaefektiivne meetod energiatarbe seisukohast. Kõigil neil taktidel, mil mikrokontroller tegeleb kasutu loendamisega, kulub energiat. Patareidega rakenduses ei ole seega soovitatav pikki tarkvaralisi viiteid teha, vaid tuleks kasutada raudvaralisi taimereid, mis töötavad iseseisvalt ning äratavad protsessori uneolekust üles, kui on vaja tööd jätkata. Tarkvaralise viite puhul on aga oluline teada, et hoolimata oma põhimõttelisest lihtsusest on see äärmiselt ebaefektiivne meetod energiatarbe seisukohast. Kõigil neil taktidel, mil mikrokontroller tegeleb kasutu loendamisega, kulub energiat. Patareidega rakenduses ei ole seega soovitatav pikki tarkvaralisi viiteid teha, vaid tuleks kasutada raudvaralisi taimereid, mis töötavad iseseisvalt ning äratavad protsessori uneolekust üles, kui on vaja tööd jätkata.
  
-===== Praktika ======+[{{  :examples:timer:timer_counter.png?300|AVR loenduri väärtuse muutusega kaasnevad sündmused}}] 
 + 
 +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. 
 + 
 +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.
  
 Järgnev programmikood käib tarkvaralise viite funktsiooni //sw_delay_ms// kohta, mis tekitab parameetriga //count// etteantud viite millisekundites. Funktsioon kasutab omakorda avr-libc teegi poolenisti assemblerkeeles kirjutatud funktsiooni //_delay_ms//. Põhjus, miks harjutuses pole kohe //_delay_ms// kasutatud, on selles, et //_delay_ms// puhul võivad pikkade viidetega probleemid tekkida. //sw_delay_ms// funktsioon võimaldab aga probleemideta kuni 65535 ms viidet. Järgnev programmikood käib tarkvaralise viite funktsiooni //sw_delay_ms// kohta, mis tekitab parameetriga //count// etteantud viite millisekundites. Funktsioon kasutab omakorda avr-libc teegi poolenisti assemblerkeeles kirjutatud funktsiooni //_delay_ms//. Põhjus, miks harjutuses pole kohe //_delay_ms// kasutatud, on selles, et //_delay_ms// puhul võivad pikkade viidetega probleemid tekkida. //sw_delay_ms// funktsioon võimaldab aga probleemideta kuni 65535 ms viidet.
  
 <code c> <code c>
-// 
 // Tarkvaraline viide millisekundites // Tarkvaraline viide millisekundites
-// 
 void sw_delay_ms(unsigned short count) void sw_delay_ms(unsigned short count)
 { {
Line 60: Line 63:
  while (count-- > 0)  while (count-- > 0)
  {  {
- // 1ms viide spetsiaalse funktsiooniga+ // 1 ms viide spetsiaalse funktsiooniga
  _delay_ms(1);  _delay_ms(1);
  }  }
Line 69: Line 72:
  
 <code c> <code c>
-// +// Kodulabori tarkvaralise viite näidisprogramm 
-// Kodulabori tarkvaralise viite demonstratsioonprogramm. +// Programm vilgutab ~1 sekundi järel hetkeks LED-i
-// Programm vilgutab ~1 sekundi järel hetkeks LED-i+
-//+
 #include <homelab/pin.h> #include <homelab/pin.h>
 #include <homelab/delay.h> #include <homelab/delay.h>
    
-// 
-// Test LED-i viigu määramine 
-// 
-pin debug_led = PIN(B, 7); 
-  
-// 
 // Põhiprogramm // Põhiprogramm
-// 
 int main(void) int main(void)
 { {
  // LED-i viigu väljundiks seadmine  // LED-i viigu väljundiks seadmine
- pin_setup_output(debug_led); + pin_setup_output(led_debug); 
- +
  // Lõputu tsükkel   // Lõputu tsükkel
- while (true)+ while (1)
  {  {
  // LED-i süütamine  // LED-i süütamine
- pin_clear(debug_led);+ pin_clear(led_debug);
    
  // Tarkvaraline paus 100 millisekundit  // Tarkvaraline paus 100 millisekundit
  sw_delay_ms(100);  sw_delay_ms(100);
    
- // LED kustutamine + // LED-i kustutamine 
- pin_set(debug_led);+ pin_set(led_debug);
  
  // Tarkvaraline paus 900 millisekundit  // Tarkvaraline paus 900 millisekundit
Line 109: Line 103:
 Kuigi näib, et LED vilgatab tõesti 1 sekundi järel, on aeg tegelikult siiski natuke pikem, sest LED-i ja viite funktsioonide väljakutsumised võtavad ka mõned mikrokontrolleri taktid aega. Kuigi näib, et LED vilgatab tõesti 1 sekundi järel, on aeg tegelikult siiski natuke pikem, sest LED-i ja viite funktsioonide väljakutsumised võtavad ka mõned mikrokontrolleri taktid aega.
  
-~~PB~~ 
-====== 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]]// 
- 
-===== 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 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}}] 
- 
-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. 
- 
-===== Praktika ===== 
  
-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).+Järgnev programmikood on taimeril põhinev ehk riistvaraline 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 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 ATmega kontrolleril
-// Riistvaraline viide millisekundites Atmega kontrolleril +
-//+
 void hw_delay_ms(unsigned short count) void hw_delay_ms(unsigned short count)
 {  {
Line 166: Line 142:
 </code> </code>
  
-~~PB~~ +Esitatud viite funktsioon kasutab aga taimerite teeki, mille lähtekood ATmega kontrollerile näeb välja järgmine:
- +
-Esitatud viite funktsioon kasutab aga taimerite teeki, mille lähtekood Atmega kontrollerile näeb välja järgmine:+
  
 <code c> <code c>
-// 
 // Taimer 0 taktijaguri valiku tüüp // Taimer 0 taktijaguri valiku tüüp
-// 
 typedef enum typedef enum
 { {
Line 186: Line 158:
 timer0_prescale; timer0_prescale;
  
-// 
 // Taimer 0 normaalrežiimi seadistamine // Taimer 0 normaalrežiimi seadistamine
-// 
 inline void timer0_init_normal(timer0_prescale prescale) inline void timer0_init_normal(timer0_prescale prescale)
 { {
Line 194: Line 164:
 } }
    
-// 
 // Taimer 0 peatamine // Taimer 0 peatamine
-// 
 inline void timer0_stop() inline void timer0_stop()
 { {
Line 202: Line 170:
 } }
  
-// 
 // Taimer 0 loenduri väärtuse määramine // Taimer 0 loenduri väärtuse määramine
-// 
 inline void timer0_set_value(unsigned char value) inline void timer0_set_value(unsigned char value)
 { {
Line 210: Line 176:
 } }
  
-// 
 // Taimer 0 ületäitumise lipukese nullimine // Taimer 0 ületäitumise lipukese nullimine
-// 
 inline void timer0_overflow_flag_clear(void) inline void timer0_overflow_flag_clear(void)
 { {
Line 218: Line 182:
 } }
  
-// 
 // Taimer 0 ületäitumise lipukese oleku lugemine // Taimer 0 ületäitumise lipukese oleku lugemine
-// 
 inline bool timer0_overflow_flag_is_set(void) inline bool timer0_overflow_flag_is_set(void)
 { {
Line 226: Line 188:
 } }
 </code> </code>
- 
-~~PB~~ 
  
 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 riistvaralise viite näidisprogramm 
-// Kodulabori riistvaralise viite demonstratsioonprogramm. +// Programm vilgutab ~1 sekundi järel hetkeks LED-i (led_debug)
-// Programm vilgutab ~1 sekundi järel hetkeks LED-i+
-//+
 #include <homelab/pin.h> #include <homelab/pin.h>
 #include <homelab/delay.h> #include <homelab/delay.h>
  
-// 
-// Test LED viigu määramine 
-// 
-pin debug_led = PIN(B, 7); 
- 
-// 
 // Põhiprogramm // Põhiprogramm
-// 
 int main(void) int main(void)
 { {
  // LED-i viigu väljundiks seadmine  // LED-i viigu väljundiks seadmine
- pin_setup_output(debug_led);+ pin_setup_output(led_debug);
  
  // Lõputu tsükkel   // Lõputu tsükkel
- while (true)+ while (1)
  {  {
- // LED-i põlema panek + // LED-i süütamine 
- pin_clear(debug_led);+ pin_clear(led_debug);
   
  // Riistvaraline paus 100 millisekundit  // Riistvaraline paus 100 millisekundit
Line 262: Line 213:
  
  // LED-i kustutamine  // LED-i kustutamine
- pin_set(debug_led);+ pin_set(led_debug);
   
  // Riistvaraline paus 900 millisekundit  // Riistvaraline paus 900 millisekundit
Line 269: Line 220:
 } }
 </code> </code>
- 
- 
et/examples/timer/delay.1412061788.txt.gz · Last modified: 2020/07/20 09:00 (external edit)
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0