- De ce Timer când avem Delay ()?
- Timere microcontroler PIC:
- Programare și explicație de lucru:
- Diagrama circuitului și simularea Proteusului:
Acesta va fi al cincilea tutorial din seria noastră de tutoriale PIC, care vă va ajuta să învățați și să utilizați cronometre în PIC16F877A. În tutorialele noastre anterioare, începusem cu Introducere în PIC și MPLABX IDE, apoi am scris primul nostru program PIC pentru a clipi LED-ul folosind PIC și apoi am realizat o secvență de clipire LED utilizând funcția de întârziere în microcontrolerul PIC. Acum, haideți să folosim aceeași secvență intermitentă cu LED-uri pe care am folosit-o în hardware-ul anterior de tutorial și cu aceasta vom învăța cum să utilizați cronometre în MCU-ul nostru PIC. Tocmai am adăugat încă un buton în placa LED pentru acest tutorial. Parcurgeți tutorialul pentru a afla mai multe.
Temporizatoarele sunt unul dintre caii de lucru importanți pentru un programator încorporat. Fiecare aplicație pe care o proiectăm va implica cumva o aplicație de sincronizare, cum ar fi activarea sau dezactivarea ceva după un interval de timp specificat. Bine, dar de ce avem nevoie de temporizatoare atunci când avem deja macrocomenzile de întârziere (__delay_ms ()) care fac același lucru !!
De ce Timer când avem Delay ()?
O macrocomandă de întârziere se numește întârziere de „dump”. Deoarece în timpul executării funcției de întârziere, MCU stă dump doar creând o întârziere. În timpul acestui proces, MCU nu poate asculta valorile sale ADC și nici nu poate citi nimic din registrele sale. Prin urmare, nu este recomandabil să utilizați funcțiile de întârziere, cu excepția aplicațiilor cum ar fi LED-urile care clipesc, unde întârzierea nu trebuie să fie precisă sau lungă.
Macro-urile de întârziere au, de asemenea, următoarele scurte veniri,
- Valoarea întârzierii trebuie să fie o constantă pentru macro-urile de întârziere; nu poate fi modificat în timpul executării programului. Prin urmare, rămâne programatorul definit.
- Întârzierea nu va fi exactă în comparație cu utilizarea cronometrelor.
- Valorile mai mari ale întârzierilor nu pot fi create folosind macro-uri, de exemplu, o întârziere de jumătate de oră nu poate fi creată de macro-uri de întârziere. Întârzierea maximă care poate fi utilizată se bazează pe oscilatorul Crystal utilizat.
Timere microcontroler PIC:
Din punct de vedere fizic, cronometrul este un registru a cărui valoare crește continuu la 255 și apoi începe din nou: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……etc.
PIC16F877A PIC MCU are trei module timer. Sunt nume ca Timer0, Timer1 și Timer2. Temporizatorul 0 și Temporizatorul 2 sunt Temporizatoare pe 8 biți, iar Temporizatorul 1 este un Temporizator pe 16 biți. În acest tutorial vom folosi Timer 0 pentru aplicația noastră. Odată ce înțelegem Temporizatorul 0 va fi ușor să lucrăm și pe Temporizatorul 1 și Temporizatorul 2.
Temporizatorul / contorul modulului Timer0 are următoarele caracteristici:
- Temporizator / contor pe 8 biți
- Citibil și scris
- Prescaler programabil software pe 8 biți
- Selectare ceas intern sau extern
- Întrerupeți la deversare de la FFh la 00h
- Selectare margine pentru ceas extern
Pentru a începe să utilizați un cronometru, ar trebui să înțelegem câțiva dintre termenii fanteziști, cum ar fi cronometrul pe 8 biți / 16 biți, Prescalerul, întreruperile temporizatorului și focalizarea. Acum, să vedem ce înseamnă cu adevărat fiecare. Așa cum am spus mai devreme, există atât temporizatoare de 8 biți, cât și 16 biți în MCU-ul nostru PIC, diferența principală dintre ele este că temporizatorul de 16 biți are o rezoluție mult mai bună decât temporizatorul de 8 biți.
Prescaler este un nume pentru partea unui microcontroler care împarte ceasul oscilatorului înainte ca acesta să ajungă la logica care crește starea temporizatorului. Gama de identificare a prescalerului este cuprinsă între 1 și 256, iar valoarea Prescalerului poate fi setată utilizând OPTION Register (Același lucru pe care l-am folosit pentru rezistențele pull up). De exemplu, dacă valoarea prescalerului este 64, atunci pentru fiecare 64 de impuls, temporizatorul va fi incrementat cu 1.
Pe măsură ce temporizatorul crește și când atinge valoarea maximă de 255, va declanșa o întrerupere și se va inițializa la 0 înapoi. Această întrerupere este numită întrerupere temporizată. Această întrerupere informează MCU că acest timp anume a scăzut.
Fosc reprezintă frecvența oscilatorului, este frecvența Crystal utilizate. Timpul necesar pentru registrul Timer depinde de valoarea Prescalerului și de valoarea Fosc.
Programare și explicație de lucru:
În acest tutorial vom seta două butoane ca două intrări și 8 LED-uri ca 8 ieșiri. Primul buton va fi utilizat pentru a seta întârzierea (500 ms pentru fiecare apăsare) și al doilea buton va fi utilizat pentru a începe să clipească secvența temporizatorului. De exemplu, dacă primul buton este apăsat de trei ori (500 * 3 = 1500ms), întârzierea va fi setată pentru 1,5 secunde și când butonul doi este apăsat, fiecare LED se va aprinde și se va opri cu întârzierea predefinită. Verificați videoclipul demonstrativ la sfârșitul acestui tutorial.
Acum, având în vedere aceste elemente de bază, să ne uităm la programul oferit la sfârșitul secțiunii Cod.
Este în regulă dacă nu ați primit programul, dar dacă ați reușit! Oferiți-vă un cookie și aruncați programul pentru a vă bucura de rezultatul dvs. Pentru alții voi împărți programul în părți semnificative și vă voi explica ce se întâmplă în fiecare bloc.
Ca întotdeauna primele câteva linii ale codului sunt setările de configurare și fișierele antet, nu voi explica acest lucru, deoarece am făcut-o deja în tutorialele mele anterioare.
Apoi, să ne omitem toate liniile și să sărim direct în funcția principală de gol, în interiorul căreia avem configurația PORT pentru Timer0.
void main () {/ ***** Configurare port pentru cronometru ****** / OPTION_REG = 0b00000101; // Timer0 cu frecvență externă și 64 ca prescalar // De asemenea, activează PULL UP TMR0 = 100; // Încărcați valoarea timpului pentru 0,0019968s; delayValue poate fi între 0-256 numai TMR0IE = 1; // Activați bitul de întrerupere a temporizatorului în registrul PIE1 GIE = 1; // Activați Global Interrupt PEIE = 1; // Activați întreruperea periferică / *********** ______ *********** /
Pentru a înțelege acest lucru, trebuie să ne uităm la Registrul OPȚIUNI din fișa noastră tehnică PIC.
Așa cum s-a discutat în tutorialul anterior, bitul 7 este utilizat pentru a permite rezistența slabă pentru PORTB. Uitați-vă la figura de mai sus, bitul 3 este făcut 0 pentru a instrui MCU că următorul prescaler care este setat ar trebui să fie utilizat pentru temporizator și nu pentru WatchDogTimer (WDT). Modul temporizator este selectat prin ștergerea bitului 5 T0CS
(OPTION_REG <5>)
Acum, bits2-0 este folosit pentru a seta valoarea prescalerului pentru temporizator. Așa cum se arată în tabelul de mai sus pentru a seta o valoare prescaler de 64, biții trebuie setați ca 101.
În continuare, să analizăm registrele asociate cu Timer0
Temporizatorul va începe să crească odată setat și să depășească după atingerea unei valori de 256, pentru a activa întreruperea temporizatorului în acest moment, registrul TMR0IE trebuie să fie setat ridicat. Deoarece Temporizatorul 0 în sine este un periferic, trebuie să activăm întreruperea periferică făcând PEIE = 1. În cele din urmă, trebuie să activăm întreruperea globală, astfel încât MCU să fie notificat despre întrerupere în timpul oricărei operațiuni, acest lucru se face făcând GIE = 1.
Întârziere = ((256-REG_val) * (Prescal * 4)) / Fosc
Formula de mai sus este utilizată pentru a calcula valoarea întârzierii.
Unde
REG_val = 100;
Prescal = 64
Fosc = 20000000
Acest lucru din calcul oferă, Întârziere = 0,0019968s
Următorul set de linii este de a seta porturile I / O.
/ ***** Configurare port pentru I / O ****** / TRISB0 = 1; // Indicați MCU-ului că pinul PORTB 0 este utilizat ca intrare pentru butonul 1. TRISB1 = 1; // Indicați MCU-ului că pinul PORTB 1 este utilizat ca intrare pentru butonul 1. TRISD = 0x00; // Indicați MCU-ului că toți pinii de pe PORT D au ieșire PORTD = 0x00; // Inițializați toți pinii la 0 / *********** ______ *********** /
Acesta este același cu cel al tutorialului nostru anterior, deoarece utilizăm același hardware. Cu excepția faptului că am adăugat un alt buton ca intrare. Acest lucru se face prin linia TRISB1 = 1.
În continuare, pe dos infinit în timp ce bucla avem două blocuri de cod. Una este utilizată pentru a obține intrarea temporizatorului de la utilizator și cealaltă pentru a executa secvența de întârziere prin intermediul LED-urilor. Le-am explicat folosind comentarii împotriva fiecărei linii.
while (1) {count = 0; // Nu rulați temporizatorul în bucla principală // ******* Obțineți întârzierea numărului de la utilizator **** ////// dacă (RB0 == 0 && flag == 0) // Când intrare dată {get_scnds + = 1; // get_scnds = get_scnds + http: // Incrementare variabilă flag = 1; } if (RB0 == 1) // Pentru a preveni creșterea continuă flag = 0; / *********** ______ *********** /
O variabilă numită get_scnds este incrementată de fiecare dată când utilizatorul apasă butonul 1. O variabilă de semnalizare (definită de software) este utilizată pentru a menține procesul de incrementare până când utilizatorul își scoate degetul de pe buton.
// ******* Executați secvența cu întârziere **** ////// în timp ce (RB1 == 0) {PORTD = 0b00000001 <
Următorul bloc intră în acțiune dacă butonul doi este apăsat. Deoarece utilizatorul a definit deja întârzierea necesară folosind butonul unu și a fost salvată în variabila get_scnds. Folosim o variabilă numită hscnd, această variabilă este controlată de ISR (Interrupt service routine).
Rutina de serviciu de întrerupere este o întrerupere, care va fi numit de fiecare dată când Timer0 este depășirilor. Să vedem cum este controlat de ISR în blocul următor, de parcă dorim să incrementăm întârzierea cu jumătate de secundă (0,5s) la fiecare apăsare a butonului, apoi trebuie să incrementăm hscnd variabilă pentru fiecare jumătate de secundă. Deoarece ne-am programat cronometrul să depășească debitul pentru fiecare 0.0019968s (~ 2ms), deci să numărăm variabila de numărare de jumătate de secundă ar trebui să fie 250 deoarece 250 * 2ms = 0.5 secunde. Deci, atunci când numărul devine 250 (250 * 2ms = 0,5 secunde), înseamnă că a trecut o jumătate de secundă, astfel încât să incrementăm hscnd cu 1 și să inițializăm numărul la zero.
void interrupt timer_isr () {if (TMR0IF == 1) // Timer flag a fost declanșat din cauza depășirii temporizatorului {TMR0 = 100; // Încărcați temporizatorul Valoare TMR0IF = 0; // Ștergeți numărul de semnal de întrerupere a temporizatorului ++; } if (count == 250) {hscnd + = 1; // hscnd va fi incrementat pentru fiecare număr de jumătate de secundă = 0; }}
Deci, folosim această valoare și o comparăm cu hscnd-ul nostru și schimbăm LED-ul nostru în funcție de timpul definit de utilizator. De asemenea, este foarte asemănător cu ultimul tutorial.
Gata, programul nostru este înțeles și funcționează.
Diagrama circuitului și simularea Proteusului:
Ca de obicei, verificăm mai întâi ieșirea folosind Proteus, am legat aici fișierele schematice ale Proteus.
Adăugați un buton la placa noastră LED anterioară și hardware-ul nostru este gata de funcționare. Ar trebui să arate cam așa:
După terminarea conexiunii, încărcați codul și verificați ieșirea. Dacă aveți vreo problemă, vă rugăm să folosiți secțiunea de comentarii. De asemenea, verificați videoclipul de mai jos pentru a înțelege întregul proces.