This shows you the differences between two versions of the page.
pm:lab:lab3-2023-2024 [2024/03/24 21:53] teodor.dicu [Fast PWM] |
pm:lab:lab3-2023-2024 [2025/03/23 22:35] (current) dan.tudose [3. Exerciții] |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ~~SHOWSOLUTION~~ | ||
+ | |||
====== Laboratorul 3: Timere, Pulse Width Modulation (PWM) ====== | ====== Laboratorul 3: Timere, Pulse Width Modulation (PWM) ====== | ||
Line 94: | Line 96: | ||
<file c> | <file c> | ||
- | /* OC1A is PB1, must be set to OUTPUT */ | + | /* OC1A is PD5, must be set to OUTPUT */ |
DDRB |= (1 << PD5); | DDRB |= (1 << PD5); | ||
/* We must choose Fast PWM 8-bit, WGMn[3:0] = 0b0101 */ | /* We must choose Fast PWM 8-bit, WGMn[3:0] = 0b0101 */ | ||
Line 112: | Line 114: | ||
Deși nu îl vom folosi la laborator, este util de știut diferențele între modul de PWM rapid și acesta care poate fi mai precis (necesar în unele aplicații, precum controlarea motoarelor). | Deși nu îl vom folosi la laborator, este util de știut diferențele între modul de PWM rapid și acesta care poate fi mai precis (necesar în unele aplicații, precum controlarea motoarelor). | ||
- | Principala diferență între acest mod și cel de Phase Correct este faptul că timer-ul va porni de la BOTTOM (i.e., poziția zero), va urca până la TOP (valoarea maximă) apoi va număra, descrescător, înapoi la BOTTOM. Comparatorul va da semnalul de output după aceiași regulă ca la Fast PWM, în funcție de rezultatul comparării cu registrul ''OCRnx''. Însă cea mai importantă diferență este faptul că valoarea lui ''OCRnx'' rămâne salvată pe toată durata unui ciclu complet, astfel se păstrează durata semnalului ON pe toată perioada //T_on + T_off// și rezultă un semnal "curat", fără decalaje ale frecvenței de PWM (de exemplu, unele frecvențe nedorite ar putea avea pierderi de energie în motoare DC). | + | Principala diferență între acest mod și cel de Fast PWM este faptul că timer-ul va porni de la BOTTOM (i.e., poziția zero), va urca până la TOP (valoarea maximă) apoi va număra, descrescător, înapoi la BOTTOM. Comparatorul va da semnalul de output după aceiași regulă ca la Fast PWM, în funcție de rezultatul comparării cu registrul ''OCRnx''. Însă cea mai importantă diferență este faptul că valoarea lui ''OCRnx'' rămâne salvată pe toată durata unui ciclu complet, astfel se păstrează durata semnalului ON pe toată perioada //T_on + T_off// și rezultă un semnal "curat", fără decalaje ale frecvenței de PWM (de exemplu, unele frecvențe nedorite ar putea avea pierderi de energie în motoare DC). |
{{.:lab3:phase_correct_pwm.png?500| Phase Correct PWM Timing}} | {{.:lab3:phase_correct_pwm.png?500| Phase Correct PWM Timing}} | ||
Line 122: | Line 124: | ||
===== 3. Exerciții ===== | ===== 3. Exerciții ===== | ||
- | Obiectivul exercițiilor este să controlăm culoarea unui LED RGB cu ajutorul PWM. Cu acest LED se poate obține orice culoare printr-o combinație de intensități pe fiecare diodă în parte! | + | Descărcați schelet codului și analizați-l: {{:pm:lab:lab3-skel.zip|schelet}} |
- | + | ||
- | Cele trei LED-uri sunt conectate la: | + | |
- | * **<color red>Red</color>**: pinul ''PD5'' are funcția ''OC1A'' (asociat Timer-ului 1); | + | |
- | * **<color green>Green</color>**: pinul ''PD7'' are funcția ''OC2A'' (asociat Timer-ului 2); | + | |
- | * **<color blue>Blue</color>**: pinul ''PB3'' are funcția ''OC0A'' (asociat Timer-ului 0); | + | |
- | + | ||
- | **Reminder**: LED-urile sunt conectate in modul anod comun / "active-low" (LED-ul este aprins atunci cand pinul aferent este LOW, si stins atunci cand pinul este HIGH). | + | |
- | + | ||
- | **Task 0**: | + | |
- | + | ||
- | - Descărcați {{:pm:lab:lab3-2023-2024:lab3-skel-2023-2024.zip|arhiva cu scheletul de cod}} și rulați exemplul. Ce observați că se întamplă pe plăcuță? | + | |
- | * Conectați-vă și verificați consola de monitorizare a serialei; vă mai amintiți de la laboratorul trecut cum se făcea temporizarea? | + | |
- | * Ce puteți spune despre comportamentul LED-ului? Ce timer este folosit și în ce mod este el configurat? | + | |
- | * Unde se modifică intensitatea? Ce input primește acea formulă și unde se folosește output-ul? | + | |
- | + | ||
- | **Task 1**: | + | |
- | + | ||
- | - Dorim să facem și culoarea **<color blue>blue</color>** să se aprindă similar; | + | |
- | * Vedeți mai sus ce timer va trebui să configurați! Folosiți tot modul Fast PWM (însă, **obligatoriu**: **citiți** și folosiți descrierea registrelor de la **Secțiunea 12.9** din [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42743-ATmega324P_Datasheet.pdf|Datasheet-ul lui ATmega324P]], acestea diferă față de cele de la Timer 1!); | + | |
- | * Faceți ca această nouă culoare să pulseze mai rapid (și în paralel) decât cea roșie! Ce observați? | + | |
- | + | ||
- | **Task 2**: | + | |
- | - Pentru a nu o supăra pe Greta Thunberg, ne trebuie și culoarea <color green>**green**</color>! Însă, cum probabil vă imaginați, este mai complicat, din cauză că GPIO-ul LED-ului ''PD7'' are outputul asociat timerului 2, însă acesta este deja folosit pentru a număra milisecundele de la momentul pornirii MCU-ului (**system ticks**)... | + | Ce timer calculează numărul de systick-uri? |
- | * No worries! Vom învăța să facem PWM manual, prin întreruperi, pe ideea: timer-ul nostru numără de la ''0'' la valoarea ''188'' apoi face Clear (executând întreruperea ''COMPA'' -- care ne incrementează ''systicks'''); | + | |
- | * Ne amintim că fiecare timer are 2 comparatoare, deci îl vom folosi pe al doilea (''COMPB'') pentru a genera o întrerupere (''TIMER2_COMPB'') la o valoare prag între ''0 -- 188'' (deci valoarea medie pentru 50% va fi ''94''); | + | |
- | * LED-ul verde va trebui aprins (deci GPIO-ul pus pe 0) din întreruperea comparatorului ''A'' (i.e., atunci când se resetează timerul) iar, la întreruperea comparatorului ''B'', va trebui oprit (i.e., GPIO setat pe 1), astfel factorul de umplere fiind dat de valoarea registrului ''OCR2B'' ;) | + | |
- | * **Atenție**: Valoarea comparatorului ''A'' va trebui să rămână tot ''OCR2A = 188'' (dorim, în continuare, să avem numărătoarea de milisecunde)! | + | |
- | **Task 3**: | + | **Task 1 (3 puncte):** |
+ | * Identificați timerul care numără systick-urile. | ||
+ | * Configurați un timer (conform descrierii pinilor) în modul Fast PWM cu ieșire inversată și prescaler 64, astfel încât LED-ul verde să pulseze ciclic de la intensitate 0 la 255. | ||
+ | * Un puls complet (de la minim la maxim sau invers) trebuie să dureze 3 secunde. | ||
+ | * La apăsarea butonului PB2, direcția de pulsare se va inversa (de la creștere la descreștere sau invers). | ||
- | - Dorim să ciclăm prin toate culorile reprezentabile folosind cele 3 LED-uri RGB. Pentru a facilita acest lucru, le vom calcula în domeniul alternativ de reprezentare **HSV** (Hue, Saturation, Value), apoi le vom converti în **RGB** pentru a le putea outputa: | + | **Task 2 (5 puncte):** |
- | * aveți formula implementată în funcția ''convert_HSV_to_RGB()''! | + | |
- | * parametrul Hue va da nuanța culorii, Saturation și Value pot fi hardcodate la 255 pentru intensitate maximă; | + | |
- | * folosiți contorul de system ticks pentru a anima schimbarea culorii, similar cum era acesta folosit pentru a pulsa intensitatea la primele exerciții (desigur, dezactivați codul ce face acest lucru). | + | |
- | {{ :pm:lab:hue-wheel.png?direct&400 |}} | + | * Folosind întreruperi (cu debouncing), configurați butoanele PB2 și PD6 pentru a regla intensitatea LED-urilor roșu și albastru. |
+ | * Inițial, ambele LED-uri pornesc cu un factor de umplere de 0%. | ||
+ | * La fiecare apăsare a butonului PB2, LED-ul roșu își crește factorul de umplere cu 25%. | ||
+ | * La fiecare apăsare a butonului PD6, LED-ul albastru își crește factorul de umplere cu 25%. | ||
+ | * Factorul de umplere va evolua astfel: 0% → 25% → 50% → 75% → 100% → revenire la 0%. | ||
+ | * Deoarece timerul 1 este folosit pentru numărarea milisecundelor (systicks), acesta nu poate fi configurat în Fast PWM. Vom învăța să implementăm PWM manual folosind întreruperi: | ||
+ | * Timerul 1 are două comparatoare; folosiți comparatorul B (COMPB) pentru a genera o întrerupere (TIMER1_COMPB) la o valoare între 0 și 1500 (valoarea medie pentru 50% fiind 750). | ||
+ | * LED-ul roșu se va aprinde la întreruperea comparatorului A (la resetarea timerului) și se va stinge la întreruperea comparatorului B, astfel încât valoarea din OCR2B să stabilească factorul de umplere. | ||
- | **Task 4 (bonus)**: | + | **Task 3 (2 puncte):** |
- | - Speaker-ul de pe placă este conectat pe pinul ''PD4'', așa cum am văzut în primul laborator. ''PD4'' este și ieșirea B a timer-ului 1, deci am putea folosi un factor de umplere de 50% pentru a produce sunet pe speaker. Scopul acestui exercițiu este să redați melodia pusă în scheletul de laborator (vedeți modulul ''sound.c''). | + | * Redați melodia din scheletul de laborator folosind speaker-ul conectat la PD4. |
- | * ''surprise_notes'' sunt diferitele note folosite, cu valorile frecvențelor în Hertzi; | + | * Nu se poate folosi timerul pentru că acesta e folosit la număratul systick-urilor. |
- | * ''durations'' este un vector cu duratele asociate fiecărei note din ''surprise_notes''; | + | * Reconfigurați timerul 0 pentru a fi folosit în modul CTC și schimbați valoarea pinului PD4 în cadrul întreruperii COMPA |
- | * ''update_notes'' va trebui să redea notele muzicale în ordinea dorită, reconfigurând timer-ul mereu | + | * Folosiți vectorii predefiniți: |
- | * Cel mai simplu va fi să reconfigurați Timer-ul 1 să fie în mod CTC, deci TOP va fi ''OCR1A'' ce va da frecveța semnalului; pentru a obține un semnal de 50%, ''OCR1B'' va trebui să fie la jumătate din valoarea primului registru; | + | * surprise_notes: note cu frecvențele (în Hertz) corespunzătoare. |
- | * Funcția ''update_notes'' va trebui apelată în bucla principală la fiecare 25ms (folosiți ''systicks'' pentru a știi când a trecut acest interval de timp de la ultimul update). | + | * durations: duratele fiecărei note. |
- | * **Atenție**: resetați ''TCNT'' la fiecare update al ''TOP''-ului! Altfel, în unele situații, va trebui să așteptați un overflow pentru ca ''TCNT'' să se reseteze. | + | * La fiecare notă, frecvența va fi setată folosind registrul OCR0A |
- | - **Bonus 2**: animarea culorilor RGB de la exercițiul anterior și redarea sunetelor trebuie să funcționeze în același timp! | + | |
- | <solution> | + | **Bonus (1 punct):** |
- | <hidden>Arhiva cu soluțiile o puteți descărca de aici: {{:pm:lab:lab3-2023-2024:lab3-solved-2023-2024-florin_s4l4m.zip}}</hidden> | + | * Redați melodia cu o viteză cu 25% mai mare decât cea inițială. |
- | </solution> | + | |
===== 4. Linkuri utile ===== | ===== 4. Linkuri utile ===== | ||
Line 185: | Line 167: | ||
===== 5. Responsabili laborator ===== | ===== 5. Responsabili laborator ===== | ||
- | * [[florin.stancu@upb.ro|Stancu Florin]] | + | * Iancu Ivasciuc |
- | * [[dicu.teodor@gmail.com|Teodor Dicu]] | + | * Andrei Zamfir |