- Zakaj časovnik, ko imamo Delay ()?
- Časovniki mikrokrmilnika PIC:
- Programiranje in delovna razlaga:
- Shema vezij in simulacija Proteusa:
To bo peta vadnica v naši vadbeni seriji PIC, ki vam bo pomagala pri učenju in uporabi merilnikov časa v PIC16F877A. V naših prejšnjih vajah smo začeli z Uvodom v PIC in MPLABX IDE, nato smo napisali svoj prvi program PIC, ki utripa LED s pomočjo PIC, nato pa naredili LED, ki utripa, z uporabo funkcije zakasnitve v mikrokrmilniku PIC. Zdaj pa uporabimo isto zaporedje utripanja LED, ki smo ga uporabljali v prejšnji strojni opremi, s tem pa se bomo naučili, kako uporabljati merilnike časa v našem PIC MCU. Za to vadnico smo pravkar dodali še en gumb na LED plošči. Če želite izvedeti več, preberite vadnico.
Časovniki so eden pomembnih delovnih konj vgrajenega programerja. Vsaka aplikacija, ki jo oblikujemo, bo nekako vključevala časovno aplikacijo, na primer vklop ali izklop nečesa po določenem časovnem intervalu. V redu, ampak zakaj potrebujemo merilnike časa, ko že imamo makroje za zakasnitev (__delay_ms ()), ki delajo isto !!
Zakaj časovnik, ko imamo Delay ()?
Makro z zamudo se imenuje zakasnitev "dump". Ker med izvajanjem funkcije zakasnitve MCU sede na smetišče tako, da samo ustvari zamudo. Med tem postopkom MCU ne more poslušati svojih vrednosti ADC ali prebrati ničesar iz svojih registrov. Zato ni priporočljivo uporabljati funkcij zakasnitve, razen za aplikacije, kot je utripanje LED, kjer časovni zamik ni nujno točen ali dolg.
Makroji za zakasnitev imajo tudi naslednje kratke prihodke,
- Vrednost zakasnitve mora biti konstanta za makre zamude; med izvajanjem programa ga ni mogoče spremeniti. Zato ostaja definiran programer.
- Zamuda ne bo točna v primerjavi z uporabo časovnikov.
- Večjih vrednosti zamud ni mogoče ustvariti z uporabo makrov, na primer zakasnitve za pol ure ni mogoče ustvariti z makri. Največja zakasnitev, ki jo je mogoče uporabiti, temelji na uporabljenem kristalnem oscilatorju.
Časovniki mikrokrmilnika PIC:
Fizično je timer register, katerega vrednost se nenehno povečuje na 255, nato pa se začne znova: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3…… itd.
PIC16F877A PIC MCU ima tri Timer moduli. So imena kot Timer0, Timer1 in Timer2. Timer 0 in Timer 2 sta 8-bitna časovnika, Timer 1 pa 16-bitni časovnik. V tej vadnici bomo za našo aplikacijo uporabili časovnik 0. Ko bomo razumeli časovnik 0, bo enostavno delati tudi s časovnikom 1 in časovnikom 2.
Časovnik / števec modula Timer0 ima naslednje funkcije:
- 8-bitni časovnik / števec
- Prebrano in zapisljivo
- 8-bitni programirljivi program za prednapenjanje
- Izberite notranjo ali zunanjo uro
- Prekinitev pri prelivanju s FFh na 00h
- Izbira roba za zunanjo uro
Če želite začeti uporabljati časovnik, moramo razumeti nekatere modne izraze, kot so 8-bitni / 16-bitni časovnik, Prescaler, prekinitve časovnika in Focs. Zdaj pa poglejmo, kaj v resnici pomeni vsak. Kot smo že omenili, so v našem PIC MCU tako 8-bitni kot 16-bitni časovniki, glavna razlika med njimi je, da ima 16-bitni timer veliko boljšo ločljivost kot 8-bitni timer.
Prescaler je ime za del mikrokrmilnika, ki deli oscilatorsko uro, preden doseže logiko, ki poveča stanje časovnika. Območje ID-ja prednapenjalnika je od 1 do 256, vrednost prednapenjalnika pa lahko nastavite s pomočjo registra OPTION (istega, kot smo ga uporabili za uporovne upore). Na primer, če je vrednost delilnika 64, nato pa za vsako 64 th bo utripala časovnika poveča za 1.
Ko se časovnik povečuje in ko doseže največjo vrednost 255, bo sprožil prekinitev in se spet inicializiral na 0. Ta prekinitev se imenuje prekinitev s časovnikom. Ta prekinitev obvesti MCU, da je ta čas pretekel.
FOSC pomeni Frekvenca oscilatorja je frekvenca kristala uporablja. Čas, potreben za časovni register, je odvisen od vrednosti prednapenjalnika in vrednosti Fosca.
Programiranje in delovna razlaga:
V tej vadnici bomo dva gumba nastavili kot dva vhoda in 8 LED kot 8 izhodov. Prvi gumb bo uporabljen za nastavitev časovne zakasnitve (500 ms za vsak pritisk), drugi gumb pa za začetek utripanja zaporedja časovnika. Na primer, če prvič pritisnete prvi gumb (500 * 3 = 1500 ms), bo zakasnitev nastavljena na 1,5 sekunde in ko pritisnete gumb dva, se vsaka LED vklopi in izklopi z vnaprej določeno časovno zakasnitvijo. Oglejte si predstavitveni video na koncu te vadnice.
Zdaj, s temi osnovami v mislih, si oglejmo naš program, podan na koncu v razdelku Koda.
V redu je, če niste prejeli programa, če pa ste ga dobili !! Dajte si piškotek in zavrzite program, da boste uživali v rezultatih. Za druge bom razdelil program na pomembne dele in vam razložil, kaj se dogaja v posameznem bloku.
Kot vedno prvih nekaj vrstic kode so nastavitve konfiguracije in datoteke z glavo, tega ne bom razlagal, saj sem to že storil v prejšnjih vajah.
Nato preskočimo vse vrstice in skočimo naravnost v glavno funkcijo void, znotraj katere imamo konfiguracijo PORT za Timer0.
void main () {/ ***** Konfiguracija vrat za časovnik ****** / OPTION_REG = 0b00000101; // Timer0 z zunanjo frekvenco in 64 kot predkalarjem // Omogoča tudi PULL UPs TMR0 = 100; // Naloži časovno vrednost za 0,0019968s; delayValue je lahko med 0-256 samo TMR0IE = 1; // Omogoči bit prekinitve časovnika v registru PIE1 GIE = 1; // Omogoči globalno prekinitev PEIE = 1; // Omogoči periferno prekinitev / *********** ______ *********** /
Da bi to razumeli, si moramo ogledati register OPTION v našem obrazcu PIC.
Kot je bilo omenjeno v prejšnji vadnici, se bit 7 uporablja za omogočanje šibkega uporovnega upora za PORTB. Oglejte si zgornjo sliko, bit 3 je narejen 0, da MCU ukaže, da je treba za nastavitev časovnika uporabljati naslednji prednamerjevalni program, ne pa za WatchDogTimer (WDT). Način časovnika je izbran s čiščenjem bita 5 T0CS
(OPTION_REG <5>)
Zdaj se bits2-0 uporablja za nastavitev vrednosti prednapenjalnika za časovnik. Kot je prikazano v zgornji tabeli, da nastavite vrednost prednapetostnega znaka 64, morajo biti biti nastavljeni na 101.
Nato si oglejmo registre, povezane s Timer0
Časovnik se bo začel povečevati, ko bo nastavljen in se bo prelival, ko bo dosegel vrednost 256, da bo omogočil prekinitev časovnika v tej točki, mora biti register TMR0IE nastavljen visoko. Ker je Timer 0 sam po sebi periferna naprava, moramo omogočiti periferno prekinitev tako, da naredimo PEIE = 1. Končno moramo omogočiti globalno prekinitev, tako da bo MCU obveščen o prekinitvi med katero koli operacijo, to storimo tako, da naredimo GIE = 1.
Zakasnitev = ((256-REG_val) * (Prescal * 4)) / Fosc
Zgornja formula se uporablja za izračun vrednosti zamude.
Kje
REG_val = 100;
Prescal = 64
Fosc = 20000000
To pri izračunu daje, Zamuda = 0,0019968s
Naslednji niz vrstic je nastavitev V / I vrat.
/ ***** Konfiguracija vrat za V / I ****** / TRISB0 = 1; // MCU naročite, da se za vhod gumba 1 uporablja zatič PORTB 0. TRISB1 = 1; // MCU naročite, da se za vhod za gumb 1 uporablja zatič PORTB 1. TRISD = 0x00; // MCU naročite, da so vsi zatiči na PORT D izhodni PORTD = 0x00; // Inicializirajte vse nožice na 0 / *********** ______ *********** /
To je enako kot v prejšnji vadnici, ker uporabljamo isto strojno opremo. Le da smo kot vhod dodali še en gumb. To naredi črta TRISB1 = 1.
Nato imamo v neskončni zanki while dva bloka kode. Ena se uporablja za vnos časovnika od uporabnika, druga pa za izvedbo zaporedja zakasnitve nad LED. Razložil sem jih z uporabo komentarjev za vsako vrstico.
medtem ko (1) {štetje = 0; // Ne zaženite časovnika, medtem ko ste v glavni zanki // ******* Pridobite zakasnitev številke od uporabnika **** ////// if (RB0 == 0 && flag == 0) // When podani vnos {get_scnds + = 1; // get_scnds = get_scnds + http: // Povečaj spremenljivko flag = 1; } if (RB0 == 1) // Za preprečitev neprekinjenega povečevanja zastavica = 0; / *********** ______ *********** /
Spremenljivka, imenovana get_scnds, se poveča vsakič, ko uporabnik pritisne gumb 1. Spremenljivka zastavica (programsko določena) se uporablja za zadrževanje postopka povečevanja, dokler uporabnik ne odstrani prsta z gumba.
// ******* Izvedite zaporedje z zakasnitvijo **** ////// while (RB1 == 0) {PORTD = 0b00000001 <
Naslednji blok začne delovati, če pritisnete gumb dva. Ker je uporabnik že določil zahtevano časovno zakasnitev s tipko ena in je bila shranjena v spremenljivko get_scnds. Uporabljamo spremenljivko, imenovano hscnd, ki jo nadzira ISR (Interrupt service rutina).
Prekinitev storitev rutinsko je prekinitev, ki se bo imenoval vsakič, ko Timer0 je preplavljena. Poglejmo, kako ga nadzoruje ISR v naslednjem bloku, kot bi radi povečali časovno zakasnitev za pol sekunde (0,5 s) pri vsakem pritisku gumba, nato pa moramo spremenljivko hscnd povečati vsake pol sekunde. Kot smo programirali, da je naš časovnik prekomerno pretočen za vsakih 0,0019968s (~ 2ms), mora biti tako štetje pol sekunde spremenljivka štetja 250, ker je 250 * 2ms = 0,5 sekunde. Torej, ko štetje dobi 250 (250 * 2ms = 0,5 sekunde), to pomeni, da je bilo pol sekunde, tako da hscnd povečamo za 1 in inicializiramo štetje na nič.
void interrupt timer_isr () {if (TMR0IF == 1) // Zastavica časovnika je bila sprožena zaradi prelivanja časovnika {TMR0 = 100; // Naloži časovnik Vrednost TMR0IF = 0; // Počisti število zastavic prekinitve časovnika ++; } if (count == 250) {hscnd + = 1; // hscnd se bo povečal za vsake pol sekunde štetja = 0; }}
Torej uporabimo to vrednost in jo primerjamo z našim hscnd in prestavimo naš LED glede na uporabniško določen čas. Prav tako je zelo podoben zadnji vadnici.
To je to, kar naš program razume in deluje.
Shema vezij in simulacija Proteusa:
Kot ponavadi najprej omogočimo preverjanje izhoda z uporabo Proteusa, sem tukaj povezal shematske datoteke Proteusa.
Dodajte gumb na prejšnjo LED ploščo in naša strojna oprema je pripravljena za uporabo. Videti bi moralo nekako takole:
Ko je povezava končana, naložite kodo in preverite izhod. Če imate kakršne koli težave, uporabite odsek za komentarje. Oglejte si tudi spodnji video, da boste razumeli celoten postopek.