Laboratorul 3: Timere, Pulse Width Modulation (PWM)

Capitole utile din Datasheet ATmega324P

  • 1. Pin Configurations
    • secțiunea 1.1 - pag. 15
  • 16. 8-bit Timer/Counter0 with PWM
    • secțiunea 16.9 - Register Description - pag. 140
  • 17. 16-bit Timer/Counter1 with PWM
    • secțiunea 17.14 - Register Description - pag. 173
  • 19. 8-bit Timer/Counter2 with PWM and asynchronous operation
    • secțiunea 19.11 - Register Description - pag. 202

1. Pulse Width Modulation

PWM (Pulse Width Modulation) este o tehnică folosită pentru a varia în mod controlat tensiunea dată unui dispozitiv electronic.

Această metodă schimbă foarte rapid tensiunea oferită dispozitivului respectiv din ON în OFF și invers (treceri rapide din HIGH în LOW, spre exemplu: 5V - 0V). Raportul dintre perioada de timp corespunzătoare valorii ON și perioada totală dintr-un ciclu ON-OFF se numește factor de umplere (duty cycle) și reprezintă, în medie, tensiunea pe care o va primi dispozitivul electronic.

Practic, se pot controla circuite analogice din domeniul digital. Spre exemplu, unui LED i se va putea controla intensitatea luminoasă, la o serie de LED-uri RGB se va putea controla precis chiar și culoarea, unui speaker – frecvența sunetului redat la un moment de timp, unui motor – viteza de rotație etc.

1.1. Principiul de funcționare

Factorul de umplere se exprimă în procente și reprezintă cât la sută din perioada unui semnal acesta va fi pe nivelul ON. În figura de mai jos, se pot observa semnale PWM cu factori de umplere diferiți. Astfel, se poate deduce foarte ușor formula pentru a obține valoarea factorului de umplere (D):

$D[\%] = \frac{t\_on}{t\_on + t\_off} \cdot 100 = \frac{pulse\_width}{period} \cdot 100$

Astfel, tensiunea medie care ajunge la dispozitiv este dată de relația: D * Vcc.

Figura 8. Semnal PWM cu diferiți factori de umplere

Modularea folosește variația factorului de umplere a unui semnal dreptunghiular pentru a genera la ieșire o tensiune analogică. Considerând o formă de undă dreptunghiulară f(t) cu o valoare minimă ymin=0 și o valoare maximă ymax și factorul de umplere D (ca în figură) valoarea medie a formei de undă e dată de relația:

$\bar{y} = D \cdot ymax$

Multe circuite digitale pot genera semnale PWM. Majoritatea microcontroller-elor oferă această facilitate, pe care o implementează folosind un numărător care este incrementat periodic (conectat direct sau indirect la o unitate de ceas) și care este resetat la sfârșitul fiecărei perioade a PWM-ului. Când valoarea numărătorului este mai mare decât valoarea de referință, ieșirea PWM (output-ul) trece din starea HIGH în starea LOW (sau invers).

Detalii

Detalii

Semnalul PWM poate fi generat și software prin mai multe metode: bit-banging, timer cu ISR. Practic orice metodă prin care se poate genera software secvența:

  • Set Pin High
  • Wait for T_on
  • Set Pin Low
  • Wait For T_off

Totuși, în multe situații se dorește o frecvență de ordinul kHz sau zeci de kHz a semnalului PWM (ex. controlul motoarelor DC sau Brushless DC), iar o astfel de metodă nu este cea mai eficientă, fiind necesară intervenția procesorului pentru tratarea întreruperilor frecvente.

2. Lucrul cu PWM pe microcontrollere AVR

În cadrul laboratorului anterior, am văzut că microcontroller-ul Atmega324 are 3 timere: Timer0 (pe 8 biți), Timer1 (pe 16 biți) și Timer2 (pe 8 biți).

Fiecare dintre aceste timere putea fi configurat în diferite moduri prin intermediul registrelor TCCRnA și TCCRnB, cu ajutorul biților WGMnx. Printre aceste moduri se numărau:

  • Normal mode
  • CTC mode (Clear Timer on Compare match) cu TOP la OCRnA
  • Fast PWM – pe care îl vom folosi noi azi!
  • Phase Correct PWM etc.

La modurile de lucru cu PWM, timer-ul va folosi unul dintre comparatoarele atașate (cu valorile din registrele OCRnA / OCRnB) pentru a stabili valoarea unui pin de output (fiecare timer are câte 2 canale de output denumite: OCnA și OCnB).

Pentru a vedea exact ce pini are asociați ca output unui timer, vedeți capitolul Pin Configurations din Datasheet-ul ATmega324P:

 PWM Output Pins

Ne vom ocupa în principal de modul Fast PWM care este utilizat pentru majoritatea aplicațiilor, mai puțin cele în care este nevoie de un control precis (de exemplu motoare BLDC, audio).

Fast PWM

La modul Fast PWM, numărarea se face doar pe frontul crescător al semnalului de ceas. Modificarea factorului de umplere se realizează instant, în schimb semnalul nu este centrat (este defazat, practic apare un “glitch” la modificarea semnificativă a factorului de umplere).

Există mai multe moduri de Fast PWM oferite de către microcontroller. De exemplu, pentru Timer-ul 1 avem:

  • Fast PWM pe 8 biți, cu valoarea de TOP = 0x00FF.
  • Fast PWM pe 9 biți, cu valoarea de TOP = 0x01FF.
  • Fast PWM pe 10 biți, cu valoarea de TOP = 0x03FF.
  • Fast PWM cu valoarea de TOP în ICR
  • Fast PWM cu valoarea de TOP în OCRnA

În acest laborator vom folosi doar modul Fast PWM pe 8 biți. Pentru variantele de Fast PWM oferite de către celelalte timere (0 și 2) și pentru celelalte moduri PWM, consultați datasheet-ul.

De exemplu, presupunem că avem Timer1 configurat pe modul de funcționare Fast PWM (modul de funcționare nu trebuie neapărat să conțină cuvântul 'PWM' ca să poată fi folosit pentru generarea unui semnal). Fast PWM este caracterizat de o frecvență fixă și un prag stabilit de programator, ce poate fi modificat în timpul execuției.

  • Modul 1 0 pentru biții COM1A1 COM1A0 va lăsa semnalul de pe pinul OC1A pe 1 în timpul numărătorii (până la atingerea pragului) și va pune semnalul pe 0 de la atingerea pragului până la capătul unui ciclu (numărare completă până la TOP).
  • Pentru a obține un factor de umplere x%, aici vom seta OCR1A = x * TOP / 100 (pentru Fast PWM, TOP poate fi 0xFF, 0x1FF sau 0x3FF, în funcție de configurația aleasă)

Exemplu de inițializare a Timer1 in modul Fast PWM 8-bit non-inverting, cu Prescaler la valoarea 1024 (frecvența PWM-ului va fi de 12MHz / 1024 / 255 ~= 45 Hz):

/* OC1A is PD5, must be set to OUTPUT */
DDRB |= (1 << PD5);
/* We must choose Fast PWM 8-bit, WGMn[3:0] = 0b0101 */
/* Note: WGM11 and WGM10 are on TCCR1A, while WGM12 and WGM13 are on TCCR1B! */
TCCR1A = (1 << WGM10);
TCCR1B = (1 << WGM12);
/* set COM1A to non-inverting output: COM1A[1:0] = 0b10 */
TCCR1A |= (1 << COM1A1);
/* Use 1024 prescaler: CS1[2:0] = 0b101 */
TCCR1B |= (1 << CS12) | (1 << CS10);
/* set duty cycle to 50%; note that we're using 8-bit mode, so TOP = 255 */
OCR1A = 127;

Phase Correct PWM

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 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).

 Phase Correct PWM Timing

Comparație între Fast PWM și Phase Correct PWM:

Fast PWM (stanga) vs. Phase Correct PWM (dreapta)

3. Exerciții

Descărcați schelet codului și analizați-l: schelet

Ce timer calculează numărul de systick-uri?

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).

Task 2 (5 puncte):

  • 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 3 (2 puncte):

  • Redați melodia din scheletul de laborator folosind speaker-ul conectat la PD4.
  • Nu se poate folosi timerul pentru că acesta e folosit la număratul systick-urilor.
  • Reconfigurați timerul 0 pentru a fi folosit în modul CTC și schimbați valoarea pinului PD4 în cadrul întreruperii COMPA
  • Folosiți vectorii predefiniți:
    • surprise_notes: note cu frecvențele (în Hertz) corespunzătoare.
    • durations: duratele fiecărei note.
  • La fiecare notă, frecvența va fi setată folosind registrul OCR0A

Bonus (1 punct):

  • Redați melodia cu o viteză cu 25% mai mare decât cea inițială.

4. Linkuri utile

5. Responsabili laborator

  • Iancu Ivasciuc
  • Andrei Zamfir
pm/lab/lab3-2023-2024.txt · Last modified: 2025/03/23 22:35 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