Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:lab:lab0-2024 [2025/03/03 13:23]
dan.tudose [5. Exerciții]
pm:lab:lab0-2024 [2026/02/27 15:46] (current)
florin.stancu
Line 323: Line 323:
     * Bitul 4 (''​PD4''​) din registrul ''​DDRD''​ va fi 0     * Bitul 4 (''​PD4''​) din registrul ''​DDRD''​ va fi 0
     * ''​DDRD &= ~(1 << PD4);''​     * ''​DDRD &= ~(1 << PD4);''​
 +  * Activati rezistenta de PULL-UP interna microcontroller-ului:​
 +    * Bitul 4 (''​PD4''​) din registrul ''​PORT''​ va fi 1
 +    * ''​PORTD |= (1 << PD4);''​
   * Pentru a determina starea de apăsare a butonului trebuie să citim valoarea pinului la care este atașat. Acesta va fi 1 atunci când butonul este liber și 0 atunci când butonul este apăsat   * Pentru a determina starea de apăsare a butonului trebuie să citim valoarea pinului la care este atașat. Acesta va fi 1 atunci când butonul este liber și 0 atunci când butonul este apăsat
     * Citim valoarea bitului 4 (''​PD4''​) din registrul ''​PIND''​     * Citim valoarea bitului 4 (''​PD4''​) din registrul ''​PIND''​
Line 376: Line 379:
  
 <​code>​ upload_protocol = urclock </​code>​ <​code>​ upload_protocol = urclock </​code>​
 +
 +Dacă doriți să folosiți alt editor de text (e.g., ''​vim''​),​ pur și simplu instalați PlatformIO din package manager-ul distribuției voastre și utilizați CLI-ul:
 +
 +<code sh>
 +pio init --board ATmega324P
 +# creați src/main.c, editați codul, adăugați în platform.ini ca mai sus
 +# apoi, pentru a compila + uploada pe placă folosiți comanda:
 +pio run -t upload
 +</​code>​
  
 === 4.3.1 Alternativă la PlatformIO: instalare separată avr-gcc toolchain === === 4.3.1 Alternativă la PlatformIO: instalare separată avr-gcc toolchain ===
Line 466: Line 478:
  
 **Task 2 (3p)** ​ **Task 2 (3p)** ​
-   * Modificați ​exemplul Hello World încât LED-ul să pâlpâie ​intermitent ​la apăsarea butonului ​BTN 1 (PB2)+   * Modificați/rescrieți programul astfel ​încât LED-ul să pâlpâie ​la interval de 500ms la apăsarea butonului PB2. La a doua apăsare, animația trebuie oprită! 
-     * Mențineți LED-ul albastru aprins. +     * Mențineți LED-ul albastru aprins; 
-     * Configurați registrele pentru a face pinul PB2 de input. +     * Configurați registrele pentru a face pinul PB2 de input; 
-     ​* Nu uitați să activați rezistența de pull-up internă a µC-ului pentru PB2.+       ​* Nu uitați să activați rezistența de pull-up internă a µC-ului pentru PB2
 +     * **Hint**: folosiți o variabilă de stare (e.g., ''​ledIsBlinking''​) pe care o inversați la apăsarea butonului;​ 
 + 
 +<note info> 
 +Observați comportamentul:​ la apăsări scurte ale butonului, există șanse ca programul să rateze schimbarea de stare și să nu aibe nici un efect. 
 +Acest lucru se întâmplă deoarece funcția de delay (''​_sleep_ms''​) este blocantă (de fapt, face busy-waiting pe procesor) iar codul cu interogarea instantanee a stării GPIO-ului de input să nu apuce să fie executat! 
 + 
 +Vom afla abia la [[:​pm:​lab:​lab3-2023-2024|laboratorul 3]] (Timers) o soluție elegantă de a face acest lucru independent și asincron. 
 + 
 +Însă avem un workaround decent: vedeți sfaturile date ultimului task bonus de mai jos și decideți dacă doriți să încercați abordarea recomandată încă de pe acum (ca bonus la 3)! 
 +</​note>​
  
 **Task 3 (5p)** ​ **Task 3 (5p)** ​
-   * Plecând de la aplicația rezultată la Task 2, pentru a implemeta un semafor cu LED-urile de culoare roșu și verde. +   * Plecând de la aplicația rezultată la Task 2, pentru a implemeta un semafor cu LED-urile de culoare roșu și verde; 
-     * Mențineți LED-ul roșu aprins la pornirea aplicației. +     * Mențineți LED-ul roșu aprins la pornirea aplicației; 
-     * La apăsarea butonului ​BTN 1 (PB2), LED-ul își va schimba culoarea în galben, după care se aprinde LED-ul verde, va sta aprins 10 secunde, după care va pâlpâi pentru 2 secunde. apoi se va stinge și se va aprinde LED-ul roșu. +     * La apăsarea butonului PB2, LED-ul își va schimba culoarea în galben, după care se aprinde LED-ul verde, va sta aprins 10 secunde, după care va pâlpâi pentru 2 secunde. apoi se va stinge și se va aprinde LED-ul roșu; 
-     * Până la terminarea secventei reapăsarea butonului BTN 1 (PB2) nu va avea niciun efect. +     * Până la terminarea secventei reapăsarea butonului BTN 1 (PB2) nu va avea niciun efect; 
-     * Hint: folosiți un automat finit pentru a implementa această funcționalitate. +     * Hint: folosiți un automat finit de stări ​pentru a implementa această funcționalitate ​;) 
-     * Hint2: pentru a obține culoarea galben, este nevoie ca și LED-ul roșu și cel verde să fie aprinse simultan.+     * Hint2: pentru a obține culoarea galben, este nevoie ca și LED-ul roșu și cel verde să fie aprinse simultan
 +     * **Bonus**: la long button press (e.g., timp de 2 secunde) să reseteze iar spre RED (însă fără a utiliza timere hardware)! 
 + 
 +<note hint> 
 +Pseudocod (sintaxă Pythonică) recomandat pentru mașina de stări: 
 +<code Python>​ 
 +# enum stări (+ un prefix): RED, GREEN, YELLOW 
 +state = SEM_RED 
 + 
 +while True: 
 +  if state == SEM_RED: 
 +    if btn_pressed(BTN1):​ 
 +      state = SEM_YELLOW 
 +    gpio_set(LED_RED,​ 0) 
 +    gpio_set(LED_GREEN,​ 0) 
 +    sleep(1ms) 
 + 
 +  if state == SEM_YELLOW:​ 
 +    # aici nu avem verificarea btn_pressed(BTN1)... 
 +    # TODO: aprindem led-ul galben, așteptăm blocant, apoi se trece in starea: 
 +    sleep(2sec) 
 +    state = SEM_GREEN 
 + 
 +  if state == SEM_GREEN:​ 
 +    # TODO: facem blink timp de 2sec și trecem în starea RED 
 +    # eventual, folosiți altă variabilă pentru a contoriza cele 2 secunde din fragmente  
 +    # (trebuie să faceți blink la LED!) 
 + 
 +</​code>​ 
 +</​note>​ 
 + 
 +<note hint> 
 +Pentru **bonus**, ținând cont că funcția de sleep este blocantă, vom simula un timer folosind conceptul de LOOP TICKS: vom putea face o aproximare a unui interval fix de timp (e.g. 1 tick = 10 ms) folosind un simplu contor în main loop, cu precizarea că nu avem voie să facem nimic time consuming în interiorul acestuia iar durata acestuia trebuie să fie aproximativ fixă (de 10 ms, în exemplul dat): 
 + 
 +<code Python>​ 
 +# exemplu (pseudocod Python) pentru blinking FSM cu ticks ca la task 2: 
 +# se poate adapta ușor și la task 3 ;)  
 +ticks = 0 
 +isLedBlinking = 0 
 +ledCurrentState = 0 
 +lastBlinkTicks = 0  # timestamp-ul (în ticks) ultimei schimbări de stare a LED-ului 
 + 
 +while True: 
 +  if btn_pressed(BTN1):​ 
 +    # inversare booleană 
 +    isLedBlinking = !isLedBlinking 
 + 
 +  if isLedBlinking:​ 
 +    # testăm dacă s-a scurs timpul (500ms) de la ultima schimbare de stare 
 +    if (ticks - lastBlinkTicks) > 50:  # ATENȚIE: 50 ticks == 500ms! 
 +      lastBlinkTicks = ticks  # salvăm timestampul evenimentului 
 +      ledCurrentState = !ledCurrentState ​ # inversăm starea LED-ului 
 +    # apoi, *mereu*, aplicăm starea curentă a LED-ului: 
 +    gpio_set(LED,​ ledCurrentState) 
 + 
 +  else: 
 +    # ne asigurăm că LED-ul e stins 
 +    gpio_set(LED,​ ledCurrentState) 
 +  # tot codul de mai ^sus^ durează câteva microsecunde 
 + 
 +  # acum contorizăm timpul la perioadă de 1 tick = 10 ms: 
 +  sleep(10ms) 
 +  ticks += 1 
 + 
 +</​code>​ 
 + 
 +Cum ne va ajuta contorizarea ticks-urilor pentru pentru determinarea unui long press? Simplu: putem verifica starea butonului la fiecare loop (deci 10ms) și reținem numărul consecutiv de bucle pentru care butonul era apăsat! Dacă acest contor ajunge să depășească 200 (ticks, deci 2000 ms) înseamnă că a avut loc evenimentul de long press. Dacă butonul a fost lăsat între timp (mai mare de 10ms pentru ca acea verificare să aibe loc), acest contor se va reseta! 
 +</​note>​
  
 ===== 6. Link-uri utile ===== ===== 6. Link-uri utile =====
Line 489: Line 578:
  
 ===== 7. Responsabili laborator ===== ===== 7. Responsabili laborator =====
-  * [[atoader@stud.acs.upb.ro | Alex Toader]] +  * [[florin.stancu@upb.ro | Florin Stancu]] 
-  * [[eduard_andrei.radu@stud.acs.upb.ro | Eduard Radu]]+  * [[jan.vaduva@upb.ro | Alex Văduva]]
   ​   ​
pm/lab/lab0-2024.1741000981.txt.gz · Last modified: 2025/03/03 13:23 by dan.tudose
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0