This shows you the differences between two versions of the page.
|
pm:lab:lab4-2023-2024 [2024/03/31 04:52] mihnea.dinica |
pm:lab:lab4-2023-2024 [2026/03/22 19:28] (current) florin.stancu |
||
|---|---|---|---|
| Line 86: | Line 86: | ||
| **F_ADC = F_CPU / PRESCALER** | **F_ADC = F_CPU / PRESCALER** | ||
| - | Alegerea prescaler-ului depinde de frecventa de esentionare si de acuratetea dorita. Cu cat prescaler-ul este mai mare frecventa ADC va fi mai mica si acuratetea va fi mai mare. Mai multe informatii se pot gasi in capitolul 23.5 din [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42743-ATmega324P_Datasheet.pdf|Datasheet ATmega324P]]. | + | Alegerea prescaler-ului depinde de frecventa de esentionare si de acuratetea dorita. Cu cat prescaler-ul este mai mare frecventa ADC va fi mai mica si acuratetea va fi mai mare. Mai multe informatii se pot gasi in capitolul 25.4 din [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42743-ATmega324P_Datasheet.pdf|Datasheet ATmega324P]]. |
| ==== Moduri de functionare ==== | ==== Moduri de functionare ==== | ||
| Line 145: | Line 145: | ||
| ADCSRA |= (1 << ADSC); | ADCSRA |= (1 << ADSC); | ||
| /* wait until conversion is complete */ | /* wait until conversion is complete */ | ||
| - | while (!(ADCSRA & (1 << ADIF))); | + | while ((ADCSRA & (1 << ADSC))); |
| uint32_t result = ADC; | uint32_t result = ADC; | ||
| </code> | </code> | ||
| Line 152: | Line 152: | ||
| Obiectivul exercitiilor este sa controlam convertorul analog-digital integrat in microprocesorul Atmega324p pentru diferite citiri (butoane multiplexate prin divizoare de tensiune, senzor de temperatura). | Obiectivul exercitiilor este sa controlam convertorul analog-digital integrat in microprocesorul Atmega324p pentru diferite citiri (butoane multiplexate prin divizoare de tensiune, senzor de temperatura). | ||
| - | Scheletul de cod {{:pm:lab:lab_4_skel.zip|}} | + | Scheletul de cod este {{:pm:lab:lab4_skel_2025-2026.zip|aici}}. |
| - | **Task 0** | + | **Task 0** (2 puncte) Completați scheletul de cod (fișierul “adc.c”) astfel încât sa definiți o funcție cu un comportament similar analogRead(uint8_t pin) → aceasta face o singura conversie a semnalului de pe pinul specificat și este blocanta pana la returnarea rezultatului. |
| - | Completați scheletul de cod (fișierul "adc.c") astfel încât sa definiți o funcție cu un comportament similar analogRead(uint8_t pin) -> aceasta face o singura conversie a semnalului de pe pinul specificat și este blocanta pana la returnarea rezultatului. | + | |
| - | **Task 1** | + | **Task 1** (1 punct) Folosind funcția anterior definită, citiți valorile de pe senzorul de temperatura (PA0). Puteti pune degetul peste el (//pe proprie răspundere (: //) și observa cum se modifica valorile. Senzorul de temperatura este ''MCP9701T-E/TT'' și are un interval de functionare de -10°C - 125°C (căutați-i datasheetul!). |
| - | Folosind funcția anterior definită, citiți valorile de pe senzorul de temperatura (PA0). Puteti pune degetul peste el (pe proprie răspundere :) ) și observa cum se modifica valorile. | + | |
| - | **Task 2** | + | <note warning> |
| - | Butoanele 1-6 sunt multiplexate pe același pin analogic (PA5) prin intermediul unui sistem de divizoare de tensiune (urmăriți schematicul pentru o explicație vizuala). Aflați ce valoare întoarce fiecare buton la apăsare și completați "define-urile" din cod. Completați codul astfel încât la apăsarea BTN2 sa se aprindă doar LED-ul roșu, la apăsarea BTN3 - LED-ul verde, iar la apăsarea BTN5 - LED-ul albastru. | + | AVR Libc are implicit o implementare simplistică a printf()-ului care nu știe să formateze valori floating point. Dacă doriți să meargă ''%f'' & friends, va trebui să activați o setare de bibliotecă prin linker-ul GCC, desigur, prin ''platformio.ini'': <code>build_flags = -Wl,-u,vfprintf -lprintf_flt -lm</code> |
| + | </note> | ||
| + | |||
| + | **Task 2** (3 puncte) Butoanele 1-6 sunt multiplexate pe același pin analogic (''PA5'') prin intermediul unui sistem de divizoare de tensiune (vedeți [[https://github.com/dantudose/PM-Board/blob/main/Hardware/schematic.pdf|schema plăcii]]). Aflați ce valoare întoarce fiecare buton la apăsare și implementați funcția ''read_btns()'' (ar trebui să întoarcă ID-ul butonului dintre cele definite). | ||
| + | |||
| + | <note tip> | ||
| + | Joculețul Snake este deja implementat în schelet (''snake .c & .h''), însă folosește perifericul SPI pentru a trimite comenzi de desenare către un controller LCD model ST7735. Protocolul acesta va fi studiat abia în [[:pm:lab:lab5-2023-2024|laboratorul 5]], așa că faceți abstracție de această componentă. | ||
| + | </note> | ||
| + | |||
| + | <note warning> | ||
| + | La o citire naivă a ADC-ului, observați că există o șansă (destul de ridicată) ca butoanele să nu fie detectate corect. Acest lucru se datorează efectului de bouncing mecanic al butonului (ADC-ul fiind suficient de rapid să sesizeze aceste schimbări). | ||
| + | |||
| + | Din păcate, un simplu debounce pe bază de timp nu va fi suficient, deoarece primele citiri ale butonului abia apăsat (până la eliminarea vibrațiilor) vor fi eronate. Sfatul ar fi să faceți mai multe citiri (într-un for), să cumulați valorile și să le filtrați (cel mai bine ar fi cu o metodă statistică, e.g. deviație standard, dar o simplă medie aritmetică va funcționa decent în majoritatea cazurilor). | ||
| + | </note> | ||
| + | |||
| + | **Task 3** (4 puncte) Configurați ADC-ul astfel încât conversia valorilor citite de pe senzorul de temperatura să se întâmple automat la interval de 1 sec. Folosiți-vă de timer1, este deja configurat să genereze întreruperi la fiecare secundă. Dacă temperatura detectată trece de un prag în grade celsius setat de voi (TEMP_THRESHOLD), dați un avertisment! Activați buzzer-ul cu funcția ''alarm()''. Hint: citiți în datasheet despre ADC Auto Trigger Enable și ADC Auto Trigger Source, care pot începe conversiile automat la apariția unui eveniment; | ||
| + | |||
| + | **Task 4 (BONUS)** (1 punct) Să zicem că vrem să vedem evoluția datelor în timp (i.e. live!). Pentru aceasta, ne putem folosi de un "Serial plotter", o aplicație ce monitorizează interfața serială și ne desenează un grafic frumos cu datele primite. Pentru VS Code, instalați extensia "Teleplot", trimiteți măsurătorile ADC cu funcția ''printf_teleplot()'', selectați extensia setand port-ul și baud rate, și veți primi un grafic în timp real. | ||
| + | |||
| + | <note info> | ||
| + | Puteți realiza ceva similar folosind Python, cu bibliotecile [[https://www.pyserial.com/docs|pyserial]] (citiți și parsați liniile Teleplot transmise de microcontroller) și [[https://learn.sparkfun.com/tutorials/graph-sensor-data-with-python-and-matplotlib/update-a-graph-in-real-time|matplotlib (exemplu animation plot)]]. | ||
| + | </note> | ||
| - | **Task 3** | ||
| - | Configurați ADC-ul astfel încât conversia valorilor citite de pe senzorul de temperatura sa se întâmple automat la interval de 1 sec. Folosiți-vă de timer1, este deja configurat sa genereze întreruperi la fiecare secunda! Hint: citiți in datasheet despre ADC Auto Trigger Enable și ADC Auto Trigger Source, care pot începe conversiile automat la apariția unui eveniment; altfel, puteți realiza manual o citire cu funcția completată in Task 0 la fiecare întrerupere de timer, caz in care nu este necesar sa completați și primele 3 funcții din scheletul task-ului 3. | ||
| ===== 5. Linkuri utile ===== | ===== 5. Linkuri utile ===== | ||
| Line 174: | Line 191: | ||
| ===== 6. Responsabili laborator ===== | ===== 6. Responsabili laborator ===== | ||
| - | * [[mihnea.dinica@stud.acs.upb.ro|Mihnea Dinica]] | + | * Alexandru Jipa |
| - | * [[cristi.tranca@gmail.com|Cristi Tranca]] | + | * Stancu Florin |