Capitole utile din Datasheet ATmega328P
I: Ce facem noi aici? Unde se foloseste ce invatam? Chiar e util?
R: Well, ca sa spunem pe scurt: “multe”, “peste tot” si “da”; ar fi raspunsurile, dar mai bine o luam pe un exemplu.
Tocmai ti-ai construit un nou PC si i-ai pus si RGB pe RAM, pe ventilatoare, pe carcasa, o gramada. Acum vine intrebarea, cine “apasa” butoanele astfel incat culorile sa iasa asa cum le pui tu in software? CPU-ul sa stea el si sa aiba grija sa schimbe culorile? Dupa mine e cam o irosire de resurse. Aici intervine un microcontroller! E un procesor mai mic, mai simplist, cu un task bine determinat in sistem. Treaba lui in cazul nostru este sa controleze RGB-ul intreaga lui viata.
TLDR, un calculator intr-un cip. Mai in detaliu, el este un circuit integrat ce reunește o unitate de procesare (CPU), memorii(volatile RAM, nevolatile EEPROM, Flash, ROM) și diverse periferice ce îi permite acestuia să comunice cu mediul extern.
Le gasim in diferite dispozitive precum: telefoane, electro-casnice, sateliti, avioane, in fabrici etc. Există o gamă largă de microcontrollere disponibile și acestea se aleg în funcție de aplicație, având în vedere mai ales optimizarea costului și a consumului energetic pentru dispozitivul unde µC urmează a fi folosit.
Perifericele reprezintă orice dispozitiv, intern sau extern, care se conectează la un sistem de calcul și îi extinde funcționalitatea de bază. În cazul microcontroller-ului, există o serie de astfel de periferice incluse direct în circuitul integrat (exemple mai sus). Deși nu seamănă cu perifericele unui PC (monitor, placă grafică, tastatură, mouse etc.), fără ele microcontroller-ul nu ar putea interacționa cu mediul exterior. Mai mult, perifericele ne ajută să conectăm alte elemente mai performante la controller si sa îi putem oferi funcționalități similare unui sistem PC (conexiune la internet, linie de date USB, display grafic etc.)
Pe parcursul semestrului vom lucra cu microcontrollere din familia AVR de la Microchip. Acestea au arhitectură Harvard pe 8 biţi şi set redus de instrucţiuni (RISC).
Cu micutul acesta vom lucra noi. Este un microcontroller pe 8 biți din familia megaAVR. Registrele şi magistrala internă de date sunt pe 8 biţi.
La acest microcontroller vom invata sa ii configuram pinii si sa interactionam cu mediul exterior din cod. Acesta are 28 de pini (prezentați mai jos), dintre care 5 sunt pentru alimentare sau funcții auxiliare, iar 23 sunt pentru I/O. microcontrollerul are patru porturi: A, B, C si D; din care doar ultimele 3 sunt accesibile noua prin pini externi.
Fundatia Arduino a creat seturi de placute de dezvoltare open source, placute pe care le vom folosi si noi la laborator. O placuta de dezvoltare este un circuit care ne pune la dispozitie facil pinii µC-ului de pe ea si care contine cirtuite de alimentare, de protectie si eventual programatorul µC-ului.
Pinout Arduino UNO:
Desi la laborator va vom pune sa lucrati direct cu adrese de memorie pentru a configura pinii si a ii controla, va vom arata cum sa folositi si un framework numit Arduino. Acesta este scris in C++ si este practic o biblioteca cu functii ajutatoare si headere (fisiere .h) cu define-uri pentru fiecare procesor in parte. Ca orice nivel de abstractizare in plus, acesta face dezvoltarea mai usoara, dar aduce si un performance penalty de chiar si 20 de ori mai incet uneori.
Pentru a putea intefața cu mediul exterior, sunt utilizate diferite componente electronice care au rol fie de actuator (modifică starea mediului exterior) sau de traductor/senzor (sunt influențate de mediul exterior și oferă informații microcontroller-ului despre diverși parametri).
Exemplu actuatori:
Exemplu Senzori:
LED-urile - Light Emitting Diode - numite și diode electroluminesciente emit lumină când ele sunt polarizate direct. A nu se confunca cu becurile deoarece au metode de functionare radical diferite.
LED-urile pot fi utilizate pe post de indicator luminos (adesea utilizate în diferite aparate pentru a semnaliza faptul că aparatul este pornit și realizează un anumit lucru), sau pentru iluminare, caz în care sunt utilizate LED-uri de putere. În cadrul laboratorului LED-urile sunt utilizate pentru a indica starea unui pin.
LED-urile sunt diode, așadar, curentul prin acestea crește exponențial cu creșterea tensiunii aplicate. Pentru a utiliza un LED pentru indicarea stării unui pin (mai degrabă spus pentru a indica prezența de tensiune), curentul prin LED trebuie limitat. Aceasta se poate realiza în cel mai simplu mod prin înserierea unei rezistențe cu LED-ul.
Un LED este proiectat să opereze la un curent nominal (ex: 10mA). Căderea de tensiune pe LED urile indicatoare, de mică putere, la acest curent este dată de chimia LED-ului, care da si culoarea acestuia. In cadrul laboratorului, deoarece folosim un LED de un curent asa mic, putem sa il alimentam direct de pe pinii logici ai µC-ului.
Schema utilizată este următoarea:
Solutie: Dacă alimentarea microcontroller-ului este de 5V pentru un LED roșu ce dorim să îl folosim la 10mA, specificat de producător cu o cădere de tensiune de 1.7V, trebuie să folosim o rezistență de 330 de ohmi.
Cel mai simplu mod de interacțiune al utilizatorului cu un microcontroller îl constituie folosirea butoanelor. Modul de conectare al unui push-button in acest laborator este dat în figura de mai jos:
a) Arată un buton conectat la pinul PD0 al µC. La apăsarea butonului, intrarea PD0 va fi legată la GND, deci va fi în starea logică “0”. Acest mod de legare este incorect deoarece atunci când butonul nu este apăsat, intrarea se află într-o stare nedefinită (ca și cum ar fi lăsată în aer), ea nefiind conectată nici la GND, nici la Vcc! Această stare se numește stare de impedanță mărită. În practică, daca am citi acum valoarea pinului, se va produce un rezultat de 1 sau 0 în funcție de condițiile de mediu. Spre exemplu, dacă apropiem degetul de acea intrare, citirea va fi 1, iar, daca îndepărtăm degetul, citirea va fi 0.
b) Arată modul corect de conectare al butonului, folosind o rezistență de pull-up între pinul de intrare și Vcc. Această rezistență are rolul de a aduce intrarea în starea “1” logic atunci când butonul este liber prin “ridicarea” potențialului liniei la Vcc. Alternativ, se poate folosi o rezistență de pull-down (conectată la GND), caz în care intrarea este ținută in starea logică “0” cât timpul butonul nu este apăsat.
La laborator: Pentru a economisi spațiu exterior, în µC-ul ATmega328P, aceste rezistențe au fost incluse în interiorul circuitului integrat. Inițial ele sunt dezactivate iar activarea acestora se poate face prin software.
Acesta poate fi considerat cel mai important pas atunci cand dorim sa folosim un µC. Trebuie sa invatam cum sa configuram intern µC-ul pentru ca sa indeplineasca functiile dorite de noi. In acest laborator vom configura pinii pentru a fi de I/O: unii pini sa citeasca daca se afla tensiune pe ei (input) sau altii sa dea 0 volti sau 5 volti in functie de comenzile noastre din software (output).
Pentru a clarifica niste terminologie: acum cand spunem ca setam un registru sau scriem intr-un registru, nu ne referim la registri de uz general din procesor cu care ati lucrat la IOCLA. Ne referim la adrese de memorie rezervate in µC. Vom repeta iarasi impreuna: “Prin registru ne referim la o adresa de memorie”. Practic cum merg lucrurile “under the hood”, la acesti bytes sunt legaturi fizice si daca scriem un bit de 1 sau de 0 in anumite pozitii, activam sau dezactivam elemente din µC.
Mereu pentru a afla cum sa configurati un periferic, datasheet-ul µC-ului este cea mai buna locatie sa aflati exact fiecare configurare unde se afla si ce face. Deoarece nu este deloc placut sa scrii in cod *(0x04) = 0b0000 0001
, producatorii de µC ofera biblioteci ( avr-libc) pentru a da nume acestor adrese. Urmatorul cheatsheet va arata cum sa configurati un anumit bit de la o anumita adresa folosind macrouri (care sunt considerate si best practice).
(1 << x)
) sau macro-ul _BV(x)
. De asemenea recomandăm folosirea numelui pinului în loc de indexul acestuia, pentru că numele acestora sunt sugestive pentru funcția pe care o îndeplinesc (spre exemplu, în registrul ADCSRA
al convertorului analog-digital, bitul ADEN
este bitul de enable). Numele pinilor, ca și în cazul registrelor, sunt deja definite în avr-libc.
Operație | Formă |
---|---|
Scriere bit pe 1 | macro |= (1 << bit_index) |
Scriere bit pe 0 | macro &= ~(1 << bit_index) |
Toggle bit | macro ^= (1 << bit_index) |
Citire bit | macro & (1 << bit_index) |
Exemplu: Lucrul cu registre
DDRB = 8; // AȘA NU. DDRB = (1 << 3); // Nici așa, este hardcodat indexul pinului. DDRB |= (1 << PB3); // AȘA DA. DDRB |= _BV(PB3); // AȘA DA.
Detalii despre lucru cu biții din registre puteți citi și la secțiunea tutoriale de pe wiki.
Nu va temeti, vom avea destule laboratoare in care sa va obisnuiti cu lucrul cu registre si configurarea µC-ului. Va incurajam sa depuneti acum la inceput niste efort pentru un drum usor in acest semestru.
Pentru acest laborator v-am scutit de cautarea in datasheet, lucru ce poate parea complicat la inceput si am sintetizat pentru voi ce adrese de memorie (registri) trebuie sa modificati pentru lucrul in acest laborator.
Microntroller-ul ATmega324 oferă 4 porturi I/O a câte 8 pini, iar intern, fiecare port are asociat trei registre a câte 8 biți prin care utilizatorul poate controla la nivel de pin fluxul datelor: poate scrie/citi date în/din portul respectiv. Aceste trei registre sunt:
DDRn
- Data Direction RegisterPORTn
- Data RegisterPINn
- Input Pins Addressn poate să fie A, B, C sau D în funcţie de portul selectat. x poate să fie între 0 și 7.
Descrierea detaliată a porturilor şi registrelor corespunzătoare acestora se găseşte în datasheet-ul ATmega324, în capitolul I/O Ports.
Să presupunem că avem un LED legat la pinul 1 al portului B (numit PORTB1
sau PB1
). Pentru a aprinde sau stinge LED-ul trebuie să urmăm următorii pași:
PB1
trebuie configurat ca ieșirePB1
) din registrul DDRB
va fi 1DDRB |= (1 « PB1);
PB1
sa ia valoarea HIGHPB1
) din registrul PORTB
va fi 1PORTB |= (1 « PB1);
PB1
sa ia valoarea LOWPB1
) din registrul PORTB
va fi 0PORTB &= ~(1 « PB1);
Să presupunem ca avem un buton legat la pinul 4 al portului D (numit PORTD4
sau PD4
), din cazul b) prezentat anterior. Pentru a determina starea butonului (apăsat sau liber) trebuie să urmăm următorii pași:
PD4
trebuie configurat ca intrarePD4
) din registrul DDRD
va fi 0DDRD &= ~(1 « PD4);
PD4
) din registrul PIND
char val = PIND & (1 « PD4);
Pe placa Arduino UNO exista un LED incorporat conectat la pinul PB5 al µC-ului. Vom scrie un program care stinge și aprinde acest LED la intervale de 500 ms, acest lucru se facandul modificând tensiunea de pe pin.
// este de preferat sa folosim macrouri pentru a nu hardcoda valori // daca vrem sa schimbam pinul, acum avem o singura linie de modificat #define LED PB5 void setup() { DDRB |= (1 << LED); // sau // DDRB |= _BV(LED); } void loop() { PORTB |= (1 << LED); // ori _BV(LED) delay(500); // functie din framework-ul de Arduino pentru a simplifica momentan programarea PORTB &= ~(1 << LED); // ori _BV(LED) delay(500); }
Cum am spus si mai devreme, acest framework aduce un nivel de abstractizare in plus ce mascheaza lucrul cu registre si operatii pe biti in spatele unor functii mai incete, dar convenabile.
Vorbiti cu asistentul de laborator pentru ce IDE va sugereaza/folosi el pentru a va putea ajuta mai usor daca intampinati dificultati.
Cel mai simplu cod de arduino ce poate fi compilat este urmatorul:
Ce poate fi tratat ca urmatorul cod clasic de C in spate:
Acestea sunt cele 3 functii de baza puse la dispozitie de framework-ul Arduino pentru a lucra cu pinii ca si I/O.
LED-ul incorporat pe placa Aduino UNO este conectat la pinul 13 in schema de notare a framework-ului Arduino.
#define LED 13 // este de preferat in continuare sa folosim macrouri, nu hardcodam valori void setup() { pinMode(LED, OUTPUT); } void loop() { digitalWrite(LED, HIGH); delay(500); digitalWrite(LED, LOW); delay(500); }
Tinkercad este un program online, gratis de modelare 3D recunoscut pentru simplitatea in utilizare. Acesta ofera suport de simulare pentru placa Arduino UNO cu anumite limitari.
Task 0 Incepem prin a verifica set-up-ul. Instalati IDE-ul dorit/folosit si rulați exemplul Hello Word cu registri pe placuta Arduino UNO din laborator. Ulterior testati si varianta in care folositi framework-ul Arduino pentru a vedea ca este oferit acelasi comportament.
Task 1 Verificati ca circuitul de pe breadboard-urile din laborator indeplineste aceleeasi functie precum circuitul din imaginea de mai sus si ca Arduino-ul este conectat la fel.
Task 2 Folosind butonul conectat la pinul digital 2 (PD2), configurati registri pentru a face pinul de input si faceti LED-ul sa se aprind cand butonul este apasat. (nu uitati sa activati rezistenta de pull-up interna µC-ului)
Task 3 Acum, folosind butonul conectat la pinul digital 3 (gasiti voi care este macroul pinului), configurati-l si pe acesta ca sa folositi butoanele pentru a creste si micsora durata delay-ului folosit la exemplul Hello Word.