- Diagrama circuitului:
- Microcontroler PIC PIC16F877A Cod de secvență intermitent LED și explicație de lucru:
În tutorialul nostru anterior, am aflat despre clipirea unui LED folosind microcontrolerul PIC și am construit același circuit pe placa Perf. Apoi am folosit PICkit 3, ICSP și MPLAB IPE pentru a arunca programul pe placa noastră Perf. Acum, în acest tutorial ne vom avansa la utilizarea mai multor pini pe microcontrolerul PIC. Vom folosi 7 ieșiri (LED-uri) și o intrare. Pentru acest tutorial vom folosi vechea placă Perf (prezentată mai jos) și vom adăuga bastoane berg pentru a scoate pinii necesari pe a doua placă LED. La sfârșitul acestui tutorial, vom genera o secvență de LED-uri intermitente folosind microcontrolerul PIC PIC16F877A și vom învăța cum să folosim mai multe intrări și ieșiri, câteva elemente de bază pentru apelarea în buclă și funcție.
Placa LED nu este altceva decât o altă placă perf, pe care vom lipi LED-urile cu un rezistor de limitare a curentului (prezentat mai jos). Vom adăuga, de asemenea, un buton pentru a iniția secvența LED intermitent.
Diagrama circuitului:
Microcontroler PIC PIC16F877A Cod de secvență intermitent LED și explicație de lucru:
Codul complet a fost dat mai jos (verificați la sfârșit), aici îl vom primi linie cu linie. Acest cod va începe să aprindă LED-uri într-o manieră secvențială atunci când este apăsat butonul. Pentru a înțelege secvențele, vă rugăm să urmăriți videoclipul de la sfârșitul tutorialului. V-aș recomanda să comparați rezultatul afișat în video cu codul de mai jos și să încercați să înțelegeți programul.
Să ne uităm la codul rând cu rând. Primele câteva linii sunt pentru configurarea biților de configurare, care au fost explicați în tutorialul anterior, așa că îi omit deocamdată. Cel mai bun mod de a înțelege orice program este să porniți de la funcția main ( void main () ), deci să facem asta
TRISB0 = 1; // Indicați MCU-ului că pinul PORTB 0 este utilizat ca intrare pentru buton. TRISD = 0x00; // Indicați MCU-ului că toți pinii au ieșire PORTD = 0x00; // Inițializați toți pinii la 0
Cuvântul TRIS este utilizat pentru a defini dacă pinul este utilizat ca intrare / ieșire și cuvântul PORT este utilizat pentru a face un pin High / Low. Linia TRISB0 = 1 va face al 0-lea pin al PORT B ca intrare. Acesta va fi butonul nostru. Liniile TRISD = 0x00; PORTD = 0x00; va face toți pinii portului D ca ieșire și va atribui o valoare inițială LOW acelor pini.
Deoarece am spus că B0 este folosit ca intrare, vom conecta un capăt al butonului la pinul B0 și altul la sol. Până atunci, ori de câte ori apăsăm butonul, pinul va fi ținut la sol, așa cum se arată în diagrama de conectare de mai sus. Dar pentru ca acest lucru să se întâmple, trebuie să folosim un rezistor de tragere, astfel încât știftul să fie ținut sus când butonul nu este apăsat. Un rezistor de tragere este ceva de genul acesta.
Dar MCU-ul nostru PIC are un rezistor intern slab de tracțiune care poate fi activat de software, economisind astfel o mulțime de probleme (atunci când vor fi conectate mai multe butoane).
Ce este un rezistor slab de tragere?
Există două tipuri de rezistențe de tragere, unul este Slab Pull Up și altul este Strong Pull Up. Rezistențele slabe de tragere au o valoare ridicată și permit astfel să curgă un curent slab, iar rezistențele puternice de tragere au o valoare scăzută, permițând astfel să curgă un curent puternic. Toate MCU folosesc în cea mai mare parte rezistențe slabe de tragere. Pentru a activa acest lucru în MCU-ul nostru PIC, trebuie să căutăm în foaia noastră de date OPTION_REG (registru de opțiuni) așa cum se arată în instantaneul de mai jos.
După cum se arată, bitul 7 se referă la rezistența slabă de tragere. Ar trebui să fie zero pentru ao activa. Acest lucru este realizat de OPTION_REG <7> = 0 . Aceasta se referă în mod specific la bitul 7 lăsând ceilalți biți la valorile sale implicite. Cu aceasta intrăm în bucla noastră while, unde verifică dacă butonul este apăsat folosind if (RB0 == 0). Dacă condiția este îndeplinită, apelăm la funcția noastră cu parametrii 1, 3, 7 și 15.
sblink (1); // FUNCTION CALL 1 cu parametrul 1 sblink (3); // FUNCTION CALL 3 cu parametrul 3 sblink (7); // FUNCTION CALL 7 cu parametrul 7 sblink (15); // FUNCTION CALL 4 cu parametrul 15
De ce folosim funcții?
Funcțiile sunt utilizate pentru a reduce numărul de linii din codul nostru. Asta ar fi știut majoritatea dintre noi. Dar de ce trebuie să reducem numărul de linii, mai ales când vine vorba de programarea MCU. Motivul este spațiul limitat în memoria noastră program. Dacă nu optimizăm corect codul, s-ar putea să rămânem fără spațiu de memorie. Acest lucru va fi util când scriem pagini lungi de coduri.
Orice funcție va avea o funcție Definiție ( sblink (int get) în cazul nostru) și o funcție Call ( sblink (1) în cazul nostru). Este opțional să aveți o declarație de funcție, pentru a o evita, am plasat definiția funcției înainte de a apela funcția în funcția mea principală.
Parametrii funcției sunt valoarea care va fi transmisă de la apelul funcției la definiția funcției. În cazul nostru, valorile întregi (1, 3, 7, 15) sunt parametrii care sunt trecuți din apelul funcției și variabila „obține” obține valoarea parametrilor în definiția funcției pentru a le procesa. O funcție poate avea mai mult de un parametru.
Odată ce funcția este apelată, liniile de mai jos din definiția funcției vor fi executate.
for (int i = 0; i <= 7 && RB0 == 0; i ++) {PORTD = get << i; // Mutare LED Secvență stânga __delay_ms (50); } pentru (int i = 7; i> = 0 && RB0 == 0; i--) {PORTD = get << i; // Mutare LED Secvență stânga __delay_ms (50); }
Acum această linie pare să fie ciudată: PORTD = get << i . Voi explica ce se întâmplă de fapt aici.
„<<” este un operator de deplasare la stânga care deplasează toți biții în poziția sa stângă. Acum, când apelăm funcția sblink (int get) cu parametrul '1' ca sblink (1), va face ca valoarea 'get' să fie 1, care în binar este 0b00000001. Prin urmare, această linie va fi ca PORTD = 0b00000001 << i .
Valoarea „i” va varia de la 0 la 7, deoarece am folosit o „pentru buclă” pentru (int i = 0; i <= 7 && RB0 == 0; i ++). Valoarea „i” fiind de la 0 la 7 va schimba rezultatul după cum urmează:
După cum puteți vedea, am pornit un LED la rând (de la stânga la dreapta), ținând restul OPRIT. Următoarea 'buclă for' pentru (int i = 7; i> = 0 && RB0 == 0; i--) , va face, de asemenea, la fel, dar de data aceasta LED-ul va fi aprins de la dreapta la stânga într-o succesiune, deoarece am început de la 7 și coborâm la 0. Am folosit o întârziere de 200ms, astfel încât să putem vizualiza LED-ul pornit și oprit.
Acum, când trecem valoarea 3 în funcția sblink (int get) , deci funcția sblink (3) va fi executată, ceea ce face ca valoarea „get” să fie 0b00000011, prin urmare rezultatul pe PORTD va fi:
Așadar, de data aceasta, două LED-uri vor fi aprinse la un moment dat folosind sblink (3). În mod similar pentru sblink (7) și sblink (15), trei și patru LED-uri vor fi aprinse într-o succesiune. Odată ce acest lucru este complet, vom face ca toate LED-urile să fie aprinse folosind linia PORTD = 0xFF . Verificați videoclipul de mai jos pentru o demonstrație completă.
Sper că ați înțeles codul și, astfel, ați învățat cum să utilizați funcțiile, bucla „pentru” și „în timp ce” pentru a obține ieșirile dorite. Acum puteți modifica codul pentru a obține diferite secvențe de LED-uri intermitente. Continuați să vă compilați codul și să îl aruncați pe MCU și să vă bucurați de ieșire. Puteți utiliza secțiunea de comentarii dacă vă blocați undeva. Am atașat aici și fișierele de simulare și program.
Asta e, deocamdată, în următorul nostru tutorial, vom învăța cum să folosim temporizatoarele PIC16F877A în loc să folosim funcțiile de întârziere. Puteți răsfoi toate tutorialele microcontrolerului PIC aici.