Implementarea software a mai multor canale PWM pe un microcontroler. Teorie. Software multicanal PWM în AVR

Destul de des pe forum apar întrebări despre implementarea Modulării în lățime a impulsurilor pe dispozitivele cu microcontroler. Eu însumi am întrebat multe despre acest lucru și, după ce mi-am dat seama, am decis să ușuresc munca noilor veniți în acest domeniu, deoarece există multe informații în rețea și sunt concepute pentru dezvoltatori de diferite niveluri și eu însumi. tocmai mi-am dat seama și memoria mea este încă proaspătă.

Deoarece cel mai important lucru pentru mine a fost folosirea PWM-ului special pentru a controla luminozitatea LED-urilor, tocmai acestea le voi folosi în exemple. Vom folosi îndrăgitul ATmega8 ca microcontroler.

În primul rând, să ne amintim ce este PWM. Un semnal PWM este un semnal de impuls cu o anumită frecvență și ciclu de lucru:

Frecvența este numărul de perioade într-o secundă. Ciclul de lucru este raportul dintre durata impulsului și durata perioadei. Le puteți schimba pe ambele, dar pentru a controla LED-urile este suficient să controlați ciclul de funcționare. În imaginea de mai sus vedem un semnal PWM cu un ciclu de lucru de 50%, deoarece durata impulsului (lățimea impulsului) este exact jumătate din perioadă. În consecință, LED-ul va fi exact jumătate din timp aprins și jumătate din timp oprit. Frecvența PWM este foarte mare și ochiul nu va observa pâlpâirea LED-ului din cauza inerției vederii noastre, așa că ni se va părea că LED-ul strălucește la jumătate din luminozitate. Dacă schimbăm ciclul de funcționare la 75%, atunci luminozitatea LED-ului va fi de 3 sferturi din plin, iar graficul va arăta astfel:

Se pare că putem regla luminozitatea LED-ului de la 0 la 100%. Acum să vorbim despre un astfel de parametru PWM precum rezoluția. Rezoluția este numărul de gradări (pași) de ajustare a ciclului de lucru, vom lua în considerare o rezoluție de 256 de pași.

Se pare că am rezolvat parametrii, acum să vorbim despre cum putem obține acest PWM de la microcontroler. Luăm un fier de lipit încălzit și ascuțit și începem să torturăm MK-ul, în același timp, conectându-ne la cele două picioare cu un osciloscop și verificând prezența unui semnal al ciclului de lucru de care avem nevoie pe ele. Microcontrolerele au suport hardware pentru PWM și mai multe canale pentru acesta, în cazul nostru 3. Anumiți pini ai microcontrolerului sunt responsabili de emiterea PWM, în cazul nostru OC2, OC1A, OC1B (15,16,17 picior în pachet DIP). Pentru aceasta se folosesc și cronometre de microcontroler, în cazul nostru TC1, TC2. Deci, cum să configurați MK-ul pentru a scoate un semnal cu ciclul de lucru necesar? Totul este foarte simplu, mai întâi să configuram picioarele de ieșire de care avem nevoie:

PORTB=0x00; DDRB=0x0E; // 0b00001110

În continuare, să începem configurarea cronometrelor. Pentru cronometrul TC1 avem nevoie de două registre: TCCR1A și TCCR1B. Deschideți fișa de date și citiți cum sunt configurate aceste registre. L-am configurat pentru un semnal PWM de 8 biți, care corespunde unei rezoluții de 256 de pași:

TCCR1A=0xA1; TCCR1B=0x09;

Pentru cronometrul TC2 vom folosi registrul TCCR2=0x69;. Configurația sa arată astfel:

TCCR2=0x69;

Gata, cronometrele sunt configurate. Ciclul de lucru va fi stabilit de registrele OCR1A, OCR1B, OCR2:

Să setăm ciclurile de lucru necesare:

OCR1A=0x32; //50 pași OCR1B=0x6A; //106 pași OCR2=0xF0; //240 de pași

Ei bine, să plasăm creșterea și decrementarea acestor registre într-o buclă infinită:

În timp ce(1) ( OCR1A++; OCR1B--; OCR2++; delay_ms(50); )

Primul program de testare este gata și pentru CVAVR arată astfel:

#include "mega8.h" #include "delay.h" void main(void) ( PORTB=0x00; DDRB=0x0E; // 0b00001110 TCCR1A=0xA1; TCCR1B=0x09; TCCR2=0x69; OCR1A=0x0x32; //0x05; pași OCR1B=0x6A //106 pași OCR2=0xF0 //240 pași în timp ce (1) ( OCR1A++; OCR1B--; OCR2++; delay_ms(50); )

Trăsături distinctive:

  • Generarea de semnale analogice folosind PWM
  • Temporizare PWM scalabilă de înaltă frecvență

Introducere

Aceste „Recomandări...” sunt linii directoare pentru utilizarea modulatorului de lățime a impulsurilor de înaltă frecvență (PWM) găsit în unele microcontrolere AVR. Ghidul include exemplu de cod de asamblare care demonstrează cum se utilizează microcontrolerul PWM de înaltă frecvență ATtiny26. Un temporizator PWM de înaltă frecvență este, de asemenea, disponibil în ATtiny15.

Pentru a genera impulsuri, se folosește un mod PWM rapid cu umplere variabilă a impulsurilor la ieșirea OC1A (PB1). Pentru a obține o undă sinusoidală dintr-un semnal digital PWM, trebuie prevăzut un filtru analogic la ieșire.

Avantajele PWM de mare viteză sunt extinderea gamei de frecvență a semnalului analogic de ieșire și posibilitatea de a folosi componente mai compacte și mai ieftine în filtru datorită frecvenței mai mari.

1. Principiul de funcționare

PWM în combinație cu un filtru analogic poate fi utilizat pentru a genera semnale analogice de ieșire, de ex. ca un convertor digital-analogic (DAC). Baza este o succesiune de impulsuri dreptunghiulare cu o perioadă de repetare constantă (frecvență de conversie fixă). Pentru a genera diferite niveluri analogice, ciclul de lucru al impulsurilor este ajustat și astfel se modifică durata impulsurilor. Dacă este necesar să se genereze un nivel analog ridicat, atunci durata pulsului este mărită și invers.

Medierea unui semnal analogic pe o perioadă (folosind un filtru analogic) generează un semnal analogic. La 50% de umplere cu impuls, semnalul analogic este egal cu jumătate din tensiunea de alimentare, iar la 75% de umplere cu impuls, semnalul analogic este egal cu 75% din tensiunea de alimentare. Exemple de filtrare a ieșirii sunt prezentate la sfârșitul acestui document.

De exemplu, un filtru trece-jos analog poate fi realizat folosind un filtru RC pasiv simplu. Filtrul elimină purtătorul PWM de înaltă frecvență și astfel produce un semnal analogic. Frecvența de setare a filtrului trebuie selectată suficient de mare pentru a nu distorsiona forma de undă a semnalului analogic. În același timp, frecvența de reglare trebuie să fie suficient de mică pentru a minimiza ondulația de la frecvența purtătoare PWM.

Figura 1. Filtru trece-jos RC

Dacă un semnal analogic este furnizat la o intrare cu impedanță scăzută, atunci trebuie conectat un amplificator tampon între ieșirea filtrului și sarcină. Acest lucru previne încărcarea condensatorului și cauzarea tensiunii de ondulare.

Figura 2 prezintă o oscilogramă reală a unui semnal PWM cu umplere variabilă a impulsului.


Figura 2. Semnal PWM cu umplere variabilă a impulsului

Microcontrolerele AVR folosesc timer-counter pentru a genera semnale PWM. Pentru a schimba frecvența purtătoarei PWM, frecvența de ceas a temporizatorului și blatul de numărare sunt modificate. O creștere a frecvenței de ceas și/sau o scădere a numărului de top duce la o creștere a frecvenței de depășire a temporizatorului și, ca urmare, frecvența PWM crește. Rezoluția maximă (count top 255) corespunde unei frecvențe maxime PWM de 250 kHz. O creștere suplimentară a frecvenței PWM este posibilă prin reducerea rezoluției, dar în acest caz numărul de pași la setarea umplerii pulsului de la 0 la 100% este redus.

Modificarea conținutului registrului de comparație (OCR) afectează umplerea pulsului. Creșterea valorii OCR crește umplerea pulsului. Până când contorul ajunge la valoarea din registrul OCR, ieșirea PWM este într-o stare ridicată, apoi scade până la atingerea vârfului numărătorului, după care contorul trece la starea zero și ciclul se repetă. Această metodă de generare în microcontrolerele AVR se numește PWM rapid.


Figura 3. Valorile contorului și ieșirea PWM

Când utilizați PWM de înaltă frecvență pentru a genera semnale analogice, lățimea nivelurilor analogice depinde de rezoluția PWM. Cu cât frecvența purtătorului este mai mare, cu atât este mai ușor să o suprimați și, prin urmare, să minimizați nivelul de ondulare. Astfel, este necesar să se optimizeze raportul dintre rezoluție și frecvența purtătoare.

2. Aplicații alternative

Cronometrul de mare viteză poate fi folosit și pentru a genera semnale digitale de înaltă frecvență, care la rândul lor sunt folosite pentru a sincroniza alte etape digitale. Prin setarea blatului de numărare foarte scăzut, pot fi generate semnale de frecvență foarte înaltă.

Frecvența maximă de ceas a temporizatorului microcontrolerului ATtiny26 este de 64 MHz (fără pre-diviziune). La o frecvență PWM de 16 MHz (număr de top 3), registrul OCR poate fi scris la 0, 1 (umplere 25%), 2 (umplere 50%, Figura 4a) sau 3 (umplere 100%). Acest lucru arată că prin scăderea vârfului de numărare, frecvența purtătoarei PWM crește.

Pentru a obține frecvența maximă de ieșire de la temporizator, acesta trebuie să fie comutat în modul non-PWM. Partea superioară a numărării și conținutul OCR trebuie să fie egal cu 0. Contorul este apoi blocat la 0. Setarea acțiunii de potrivire la „comutați ieșirea” face ca ieșirea să fie inversată (comutată) la fiecare bifare a cronometrului. Ca rezultat, se obține o frecvență de 32 MHz (Figura 4b).


Figura 4. Ieșire digitală de înaltă frecvență

3. Exemplu de aplicare

Figura 4 ilustrează cum se generează o undă sinusoidală dintr-un semnal PWM de înaltă frecvență.

Codul programului constă din 3 părți: inițializare, procedura de gestionare a întreruperilor de depășire a temporizatorului 1 și bucla în modul de repaus. Acest exemplu presupune că microcontrolerul funcționează la o frecvență de ceas de 8 MHz.


Figura 5. Schema bloc a ciclului principal al programului de generare a semnalului sinusoidal

3.1. Inițializare

Ieșirea Timer Comparator 1 (OC1A) trebuie configurată ca ieșire.

În continuare, este setat temporizatorul 1: este pregătită sursa ceasului cronometrului - este lansat circuitul PLL, care trebuie să intre în sincronizare (captură) cu frecvența ceasului sistemului. PLL-ul necesită aproximativ 100 ms pentru a captura la ceasul sistemului și, prin urmare, trebuie să aștepte până când indicatorul de capturare PLL este setat înainte de a continua. Odată capturat PLL-ul, acesta trebuie selectat ca sursă de ceas temporizator.

Apoi, modul PWM este selectat cu inversarea ieșirii OC1A prin coincidență, iar topul de numărare este setat la 0xFF. Valoarea vârfului de numărare determină rezoluția și frecvența purtătoare a PWM - cu cât valoarea vârfului este mai mare, cu atât rezoluția este mai mare și frecvența purtătoarei este mai mică.

Cronometrul este acum gata de pornire: setarea prescalerului pornește cronometrul. În cele din urmă, întreruperea timer overflow este activată.


Figura 6. Procedura de inițializare (inițializează pinul și temporizatorul 1 pentru o funcționare rapidă PWM)

3.2. Întrerupeți rutina

Când temporizatorul 1 atinge valoarea de la OCR1C (0xFF), este apelată rutina de întrerupere a temporizatorului de depășire. Deoarece valoarea OCR1C este o constantă, acest eveniment are loc cu frecvență constantă. Această perioadă determină frecvența purtătoare a semnalului PWM de ieșire.

Rutina de procesare a întreruperii implementează un tabel pentru generarea unui semnal sinusoidal. De fiecare dată când se intră în procedură, indicatorul de acces la tabel este incrementat, astfel încât să fie încărcate noi valori de fiecare dată. Valoarea citită din tabel este scrisă în registrul OCR1A. În acest fel, trenul de impulsuri generat poate fi convertit într-un semnal sinusoidal. Rețineți că registrul OCR1A este tamponat și că o rescrie din registrul tampon în registrul real OCR1A are loc atunci când temporizatorul depășește.

Este nevoie de 13 cicluri de ceas pentru a finaliza rutina de procesare a întreruperii. Apelarea unei proceduri și revenirea din aceasta necesită, de asemenea, timp - sunt necesare un total de 21 de cicluri. Deoarece Timer 1 este de 8 biți, întreruperea are loc la fiecare 256/(PWM_Frequency/System_Frequency) cicluri de ceas. Acest exemplu presupune tactarea de către un oscilator RC intern cu o frecvență de 8 MHz. Dacă se utilizează frecvența maximă de ceas PWM de 64 MHz, atunci apare o depășire a temporizatorului la fiecare 32 de ceasuri de sistem.

Deși poate fi tactat la o frecvență maximă de 64 MHz, în acest exemplu se presupune că frecvența ceasului cronometrului este de 4...16 MHz pentru a demonstra în continuare funcționarea cu un prescaler.


Figura 7. Diagrama bloc a procedurii de procesare a întreruperilor timer overflow

3.3. La ralanti

În timp ce se așteaptă să apară o întrerupere, microcontrolerul este pus într-un mod de repaus economic „Idle”. Când procesarea întreruperii este finalizată, microcontrolerul revine în modul de repaus.

4. Oscilograme

Următoarele figuri prezintă oscilograme ale generării de semnale sinusoidale folosind microcontrolerul ATtiny26. Formele de undă arată două semnale: un semnal digital de la ieșirea OC1A și un semnal PWM procesat/filtrat. Pentru a genera un semnal sinusoidal analog, a fost folosit un filtru RC simplu cu parametrii R = 10 kOhm și C = 100 nF, care corespund unei frecvențe de reglare a filtrului de 1 kHz. Astfel, unda sinusoidală este trecută și frecvența purtătoare de înaltă frecvență este suprimată.


Figura 8. Ieșire filtrată și nefiltrată OC1A


Figura 9. Ieșire filtrată și nefiltrată OC1A (la scară mare)

Am atins subiectul utilizării contorului/temporizatorului ATtiny13 în modul normal și în modul de numărare a impulsurilor (CTC). În acest articol continui tema cronometrului, dar acum ne vom uita la utilizarea lui pentru implementarea modulării lățimii impulsului (PWM).

Toate microprocesoarele funcționează cu semnale digitale, de ex. cu zero logic (0 V) și unul logic (5 V sau 3,3 V). Dar dacă vrem să obținem o valoare intermediară ca rezultat? În astfel de cazuri, utilizați Modularea lățimii impulsului(PWM, în engleză Pulse-width modulation (PWM)) este procesul de control al puterii furnizate sarcinii prin modificarea ciclului de lucru al impulsurilor la o frecvență constantă.
Modularea lățimii impulsului este un semnal de impuls periodic. Există PWM digital și analogic, unipolar și bipolar etc. Dar principiul funcționării lor rămâne același indiferent de design și constă în compararea a două tipuri de semnale: de referință (pulsuri dinți de ferăstrău sau triunghiulare) și de intrare (constante sau variabilă după cum este necesar, în funcție de sarcina PWM specifică). Aceste semnale sunt comparate și, atunci când se intersectează, nivelul semnalului la ieșirea PWM se modifică. Tensiunea de ieșire PWM are forma de impulsuri dreptunghiulare prin modificarea duratei acestora, putem ajusta valoarea medie a tensiunii la ieșirea PWM *.

* Dacă utilizați un circuit RC integrator la ieșirea PWM, atunci în loc de unul în impuls puteți obține o tensiune constantă a valorii dorite. Dar în exemplul nostru cu LED-uri, puteți face fără acest lucru, deoarece ochiul uman nu va putea discerne pâlpâirea LED-ului la frecvența de ceas utilizată.

Parametrii PWM

  • T - perioada de ceas (semnal de referință);
  • t - durata pulsului;
  • S - ciclu de lucru;
  • D - factor de umplere.

Ciclul de lucru este determinat de raportul dintre perioada și durata impulsului. Factorul de sarcină este reciproca ciclului de lucru (poate fi exprimat ca procent):

S=T/t=1/D

Să aruncăm o privire mai atentă asupra modului în care funcționează PWM în microcontrolerele AVR, folosind ATtiny13 ca exemplu.
După cum sa menționat în exemplul anterior, ATtiny13 implementează două tipuri de PWM: așa-numitul „PWM rapid” și „PWM corect de fază”. Ambele opțiuni se bazează pe utilizarea unui contor/temporizator de opt biți T0 încorporat în MK. Temporizatorul este folosit aici în locul unui semnal de referință. Frecvența de ceas a temporizatorului este setată de prescalerul de ceas al procesorului sau de la un generator de ceas extern. Modul de ceas este specificat prin biți CS02 (2), CS01 (1), CS00(0) înregistrare TCCR0B:

  • 000 - temporizator/contor T0 oprit
  • 001 - generator de ceas CLK
  • 010 - CLK/8
  • 011 - CLK/64
  • 100 - CLK/256
  • 101 - CLK/1024
  • 110 - de la o sursă externă la pinul T0 (pin 7, PB2) prin declinul semnalului
  • 111 - de la o sursă externă la pinul T0 (pin 7, PB2) în ordinea crescătoare a semnalului

Setarea temporizatorului pentru PWM

Modul de funcționare a temporizatorului este specificat prin biți WGM01(1) și WGM00(0) înregistrare TCCR0A:

  • 00 - modul normal
  • 01 - Modul de corectare a fazei PWM
  • 10 - modul de numărare a impulsurilor (resetat dacă coincide)
  • 11 - Modul PWM

Aici ne interesează opțiunile „01” și „11”.

Biți COM0A1(7) și COM0A0(6) înregistrare TCCR0A setați ce semnal va apărea la pinul OC0A (pin 5, PB0) când contorul se potrivește (înregistrați TCNT0) cu registrul de comparație A ( OCR0A).

În modul „Fast PWM”:

  • 10 - setarea 0 pe pinul OC0A când se potrivește cu A, setarea 1 pe pinul OC0A când contorul este resetat (mod non-invers)
  • 11 - setarea 1 pe pinul OC0A când se potrivește cu A, setarea 0 pe pinul OC0A la resetarea contorului (mod invers)
  • 00 - pinul OC0A nu funcționează
  • 01 - dacă bitul WGM02 al registrului TCCR0B este setat la 0, pinul OC0A nu funcționează
  • 01 - dacă bitul WGM02 al registrului TCCR0B este setat la 1, inversați starea pinului OC0A când se potrivește A
  • 10 - setarea 0 pe pinul OC0A dacă coincide cu A în timp ce valoarea contorului este în creștere, setarea 1 pe pinul OC0A dacă coincide cu A în timp ce valoarea contorului este în scădere (mod non-invers)
  • 11 - setarea 1 pe pinul OC0A dacă coincide cu A în timp ce valoarea contorului este în creștere, setarea 0 pe pinul OC0A dacă coincide cu A în timp ce valoarea contorului este în scădere (mod invers)

Biți COM0B1(5) și COM0B0(4) registre TCCR0A setați ce semnal va apărea la pinul OC0B (pin 6, PB1) când contorul se potrivește (înregistrați TCNT0) cu registrul de comparație B ( OCR0B).

În modul „Fast PWM”:

  • 01 - rezervă
  • 10 - setarea 0 pe pinul OC0B când se potrivește cu B, setarea 1 pe pinul OC0B când contorul este resetat (mod non-invers)
  • 11 - setarea 1 pe pinul OC0B la potrivirea cu B, setarea 0 pe pinul OC0B la resetarea contorului (mod invers)

În modul „PWM cu corecție de fază”:

  • 00 - Pinul OC0B nu funcționează
  • 01 - rezervă
  • 10 - setarea 0 pe pinul OC0B dacă coincide cu B în timpul creșterii valorii contorului, setarea 1 pe pinul OC0B la potrivirea cu B în timpul scăderii valorii contorului (mod non-invers)
  • 11 - setarea 1 pe pinul OC0B când coincide cu B în timp ce valoarea contorului crește, setarea 0 pe pinul OC0B când se potrivește cu B când valoarea contorului este în scădere (mod invers)

PWM rapid

În acest mod, contorul numără de la zero la maxim. Când valoarea contorului este setată la zero, la ieșire apare un impuls (este setată o unitate logică). Dacă se potrivește cu registrul de comparație, pulsul este resetat (este setat un zero logic). În modul invers, opusul este adevărat.

PWM cu corecție de fază (PWM corect de fază)

În acest mod, contorul numără de la zero la maxim, iar apoi în direcția opusă, până la zero. Dacă coincide cu registrul de comparație în timpul creșterii valorii contorului, pulsul este resetat (se setează un zero logic). Dacă există o coincidență în timpul scăderii, apare un impuls (este setată o unitate logică). În modul invers, opusul este adevărat. Dezavantajul acestui mod este că frecvența ceasului este redusă la jumătate față de modul Fast PWM. Dar când ciclul de funcționare se schimbă, centrele impulsurilor nu se deplasează. Scopul principal al acestui mod este de a face semnale PWM multifazate, de exemplu o undă sinusoidală trifazată, astfel încât atunci când ciclul de lucru se schimbă, unghiul de defazare dintre două semnale PWM să nu se schimbe.

Pentru a vedea clar cum funcționează PWM, să scriem un mic program (eu efectuez toate experimentele pe placa mea de depanare, așa că dau codul în legătură cu acesta):

/* * tiny13_board_pwm * Firmware-ul demonstrativ al plăcii de depanare ATtiny13. * Demonstrarea funcționării PWM pe două canale: * semnal non-invers la ieșirea OC0A, semnal invers la ieșirea OC0B. */ #define F_CPU 1200000UL #include #include #define LED0 PB0 // OC0A #define LED1 PB1 // OC0B int main(void) ( // LED-uri: DDRB |= (1)<< LED0)|(1 << LED1); // выходы = 1 PORTB &= ~((1 << LED0)|(1 << LED1)); // по умолчанию отключены = 0 // Таймер для ШИМ: TCCR0A = 0xB3; // режим ШИМ, неинверсный сигнал на выходе OC0A, инверсный - на выходе OC0B TCCR0B = 0x02; // предделитель тактовой частоты CLK/8 TCNT0=0; // начальное значение счётчика OCR0A=0; // регистр совпадения A OCR0B=0; // регистр совпадения B while(1) { do // Нарастание яркости { OCR0A++; OCR0B = OCR0A; _delay_ms(5); } while(OCR0A!=255); _delay_ms(1000); // Пауза 1 сек. do // Затухание { OCR0A--; OCR0B = OCR0A; _delay_ms(5); } while(OCR0A!=0); _delay_ms(1000); // Пауза 1 сек. } }

Aici vedem că atunci când pornește MC, registrele de comparație A și B sunt setate la 0, iar contorul pornește în modul Fast PWM, generând un semnal PWM non-invers la ieșirea OC0A și unul invers la ieșirea OC0B. În bucla principală, valorile registrelor de comparație se schimbă ușor de la 0 la maxim și înapoi. Drept urmare, LED-urile conectate la pinii OC0A și OC0B se vor aprinde alternativ și se vor stinge lin, parcă în antifază.
Dar dacă te uiți mai atent, vedem că unul dintre LED-uri nu se stinge complet, ci continuă să strălucească slab. Această caracteristică este tipică pentru modul Fast PWM. Cert este că în acest mod, chiar dacă scrieți 0 în registrul de comparație, atunci când contorul este resetat la zero, la ieșire este încă setat unul logic, care este resetat în următorul ciclu de ceas (coincidend cu registrul de comparație ). Astfel, în fiecare perioadă va exista un impuls scurt cu o durată de 1 ciclu de ceas, dar acesta este suficient pentru a ilumina LED-ul. Acest efect este absent în modul invers de generare a impulsurilor de ieșire, deoarece în acest caz, când contorul este resetat, nu va exista un puls scurt, ci, dimpotrivă, o scurtă înclinare în timpul umplerii maxime a PWM-ului. Această scădere poate fi văzută pe un osciloscop, dar vederea umană pur și simplu nu va observa o astfel de pâlpâire a LED-ului. Prin urmare, al doilea LED se aprinde și se stinge complet. În modul PWM cu corecție de fază, acest efect este absent indiferent dacă semnalul invers este generat sau nu la ieșire. Să schimbăm valoarea biților WGM01(1) înregistrare TCCR0A de la 1 la 0.

PWM (PWM) - modularea lățimii impulsului. Nu este nevoie să fii intimidat de acest termen. Aceasta este doar o modalitate de a regla tensiunea. Să presupunem că lumina de fundal a monitorului este prea puternică, modificați luminozitatea. Dar ce se întâmplă cu adevărat în acest moment?

Să ne imaginăm că lumina de fundal a monitorului este de mai multe LED-uri. Totul este alimentat de tensiune constantă. Dar trebuia să reducem luminozitatea monitorului. Este logic să răspundem că acest lucru se poate face cu un rezistor variabil. La curenți scăzuti este posibil. Dar la cele mai mari, rezistența se va încinge foarte mult. Dimensiunile, pierderile și consumul de energie vor crește semnificativ.

Prin urmare, oamenii au venit cu un circuit tranzistor care transformă o tensiune DC într-una pulsatorie. Se dovedește că tensiunea pulsatorie, în funcție de umplerea perioadei, va fi echivalentă cu o tensiune constantă. Acestea. Dacă într-o perioadă tensiunea a fost pornită 50% din timp și oprită 50%, atunci tensiunea DC echivalentă ar fi egală cu 50% din tensiunea nominală.

În cifre, este simplu - a existat o tensiune de 5 V DC, am condus-o prin PWM - am primit 2,5 V. Dacă ciclul de lucru al impulsului este de 75%, atunci tensiunea DC echivalentă va fi de 3,75 V. Cred că ideea este clară.

Acum să trecem la implementarea practică. Folosind un microcontroler, vom schimba umplerea de la 0 la 100%, apoi de la 100% la zero. Rezultatul final ar trebui să arate astfel:

Pentru a fi mai clar, haideți să conectăm un LED. Ca rezultat, LED-ul se va aprinde și se va stinge fără probleme.

Să lansăm CodeVision-ul nostru preferat. Creăm un proiect folosind vrăjitorul. În secțiunea Timer, selectați Timer 2 și setați setările ca în figură.

Dacă încercați să generați un proiect, programul poate jura. Suntem de acord, deoarece avem piciorul 3 al portului B care ar trebui configurat ca ieșire.

Aducem codul în următoarea formă:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include void main(void) (PORTB= 0x00; DDRB= 0x08; // Inițializare Timer/Counter 2 ASSR= 0x00 ; TCCR2= 0x6C; TCNT2= 0x00; OCR2= 0x00; TIMSK= 0x00 ; în timp ce (1) (); )

#include void main(void) ( PORTB=0x00; DDRB=0x08; // Timer/Counter 2 initialization ASSR=0x00; TCCR2=0x6C; TCNT2=0x00; OCR2=0x00; TIMSK=0x00; while (1) ( ); )

Să fim atenți la linia OCR2=0x00; Această variabilă este tocmai responsabilă pentru cantitatea de umplere a pulsului. Această valoare se modifică de la 0 la 255(0xFF), adică 255 corespunde umplerii 100% (curent constant). Prin urmare, dacă aveți nevoie de umplere 30% (255/100)*30=77. Apoi, convertiți 77 în sistemul hexazecimal OCR2=0x4D;

TCCR2=0x6C; Schimbând această valoare putem regla frecvența PWM. Frecvența de operare PWM este un multiplu al frecvenței la care funcționează microcontrolerul. Proiectul a folosit o frecvență de microcontroler de 8 MHz, a fost folosită o frecvență PWM de 125 kHz, prin urmare divizorul este 8/125 = 64
0x6C în sistemul de numere binare 1101100, deschideți foaia de date pe Atmega8 și vedeți descrierea registrului TCCR2, deci aici este 1101 100 ultimele cifre sunt 100 și sunt responsabile pentru selectarea frecvenței de operare PWM

Să trecem direct la program:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include #include void main(void) ( PORTB= 0x00 ; DDRB= 0x08 ; ASSR= 0x00 ; TCCR2= 0x6C ; TCNT2= 0x00 ; OCR2= 0x00 ; TIMSK= 0x00 ; while (1 ) ( while (OCR2)< 0xff ) { OCR2= OCR2+ 0x01 ; delay_ms(5 ) ; } while (OCR2>0x00 ) ( OCR2= OCR2- 0x01 ; delay_ms(5 ) ; ) ) ; )

#include #include void main(void) ( PORTB=0x00; DDRB=0x08; ASSR=0x00; TCCR2=0x6C; TCNT2=0x00; OCR2=0x00; TIMSK=0x00; while (1) ( while(OCR2)<0xff) { OCR2=OCR2+0x01; delay_ms(5); } while(OCR2>0x00) ( OCR2=OCR2-0x01; delay_ms(5); ) ); )

Codul este incredibil de simplu: mai întâi, într-o buclă, creștem umplerea de la 0 la 255(ff), apoi o reducem de la 255 la 0.
Și, în sfârșit, un videoclip despre cum ar trebui să funcționeze totul. mult succes la studii)

PWM- Modularea lățimii impulsului
PWM- Modularea lățimii impulsului (adică la fel ca PWM)

Ce este PWM și de ce este necesar?

De ce aveți nevoie de software PWM?

Apoi, pe AVR (Atmega) în sine există 1-2 canale shim, ceea ce adesea nu este suficient pentru ceea ce este necesar.

Să avem 3 (trei) LED-uri și vrem să controlăm luminozitatea fiecăruia în mod individual. Canalele de cronometru PWM încorporate nu sunt suficiente. Și, în general, poate că vrem în continuare să exercităm un control special asupra fiecăruia dintre ei. Prin urmare, le punem pe picioare normale (în exemplul PORTC, picioarele 3,4,5) și le controlăm programatic.

Informații suplimentare despre conexiune: http://www.radiokot.ru/start/mcu_fpga/avr/05/ și în fișa de date pentru controler.

Calculul unui rezistor pentru un LED:

Putere: 5V. Căderea de tensiune pe LED poate fi considerată 1,5V. Curentul de pe LED nu ar trebui să fie mai mare de 20mA (unii vor argumenta că este nevoie de 15mA, dar îmi place mai luminos).
Conform legii lui Ohm: I=U/R, R=U/I=(5-1,5)/0,02=175 Ohm. Am instalat rezistențe R1, R2 și R2 - 220 Ohmi.

Algoritm

Cea mai simplă opțiune este un ciclu etern. Opțiunea cu întrerupere va fi mai târziu (mai jos), acum să ne uităm la un exemplu simplu pentru a înțelege esența.

În primul rând, trebuie să determinați două lucruri: la ce frecvență vor clipi LED-urile, astfel încât această clipire să nu fie vizibilă și, în al doilea rând, câte niveluri de luminozitate poate avea LED-ul.

În ceea ce privește nivelurile de luminozitate, să fie 256. 0 - complet oprit, 255 - complet pornit (adică canalul PWM este în cel logic tot timpul, adică ciclul de lucru = 100%.

Totuși, acum o să vă încurc puțin.

Ideea este că avem PLUS-ul diodei din circuit conectat direct la sursa de alimentare, iar minusul trece prin rezistor la picior (unde este rezistorul nu contează, ceea ce contează este ceea ce este la piciorul MK) . Prin urmare, LED-ul se aprinde atunci când nivelul de pe piciorul MK este scăzut, adică. zero, adică piciorul din interiorul MK este aruncat la GND, i.e. la pamant. Aceasta înseamnă că 0-urile și 1-urile din PWM trebuie de fapt să fie inversate. Acestea. Cu cât semnalul conține mai mult 0s față de 1s, cu atât dioda va fi mai strălucitoare.

Și astfel, există 256 de niveluri de luminozitate.

Despre ce fel de clipire vorbim? Concluzia este că, dacă trebuie să aplicăm un semnal PWM la mai multe diode și să facem acest lucru secvențial pentru fiecare, atunci după ce ieșim semnalul către prima diodă trebuie să revenim la ieșirea semnalului către aceasta într-un astfel de timp încât:

  1. au timp să genereze un semnal PWM cu drepturi depline,
  2. nu a trecut mai mult de 1/25 de secundă, altfel LED-ul va clipi vizibil,
  3. Nu au existat pauze vizibile în generarea PWM între segmentele semnalului PWM, de exemplu. astfel încât semnalul PWM NU SĂ ESTE DISTORSAT.

Iată un exemplu de distorsiune a semnalului PWM:

Vom ține cont de toate acestea, dar de fapt nu este important pentru noi aici, deoarece vom avea un intermitent foarte simplu și neted și va schimba doar luminozitatea, adică. va fi mult timp, iar sarcina este atât de simplă încât nu va consuma timp de la generarea semnalului PWM.

Și așa, iată codul sursă (pentru AVR studio, adică gcc):

#define F_CPU 1000000UL #include #include #define LEDS_N 3 #define LEDS_PORT PORTC #define LEDS_DDR DDRC int main() ( înregistrează unsigned char scancounter=0; înregistrează unsigned char i; înregistrează unsigned char glow=0; unsigned char level=(0,16,32); // care parte din toate ciclurile led-ul este ON unsigned char ledbits=(0b00001000,0b00010000, 0b00100000) // setează direcția C5 - ieșire LEDS_DDR=0b11111111 // stinge toate LED-urile pentru partea principală = 01111; ;i =level[i])( // off - pornește pin LEDS_PORT|=ledbits[i]; ) else ( // on - dezactivează pin LEDS_PORT&=~ledbits[i]; ) ) scancounter++; // luminozitatea ledului se schimbă dacă (!scancounter)( pentru (i=0;i 128)nivel[i]=0; ) ) ) )

Cum funcționează programul

Există un numărător de interval de timp - scancount. Valoarea maximă a acestui contor este numărul de niveluri de luminozitate minus 1. La fiecare rotație a ciclului crește cu unu, apoi depășește 255 și devine din nou 0. La fiecare rotație a ciclului, se setează un semnal pentru fiecare LED. Dacă contorul este mai mic sau egal cu nivelul de luminozitate, atunci opriți dioda. Dacă contorul este mai mic decât nivelul de luminozitate specificat pentru diodă, atunci porniți dioda. Și ca fiecare ciclu. De exemplu, dacă nivelul de luminozitate este 0, atunci contorul va fi întotdeauna egal sau mai mare decât zero, iar dioda va fi întotdeauna oprită. Dacă nivelul de luminozitate este de 255, atunci contorul va fi mai mic decât această valoare 254 din 255 de rotații ale contorului și va arde la intensitate aproape maximă. Dacă luminozitatea este setată la 50, atunci pentru primele 50 de rotații ale ciclului dioda va fi pornită, iar pentru restul de 206 de rotații va fi oprită, de exemplu. I se va furniza 50/256 din curentul maxim.

Mai jos în program controlăm nivelul de luminozitate al diodei, astfel încât să existe un fel de demonstrație. La fiecare depășire a contorului, se adaugă 1 la luminozitatea tuturor diodelor, dar dacă luminozitatea devine mai mare de 128, atunci este resetat la 0. În general, dacă această verificare nu a existat, atunci după atingerea nivelului de luminozitate de 255 ar fi resetat la zero, dar experiența a arătat că după o luminozitate de 128 crește atât de imperceptibil încât putem presupune că la o valoare de 128 este deja aproape maximă. Și pentru ca efectul rezultat să fie mai dinamic, a fost introdusă această verificare.

De asemenea, trebuie să știți că dependența luminozității de curent pentru LED-uri NU este LINEARĂ. Acestea. 128 nu este de două ori mai slab decât 255 și nici de două ori mai luminos decât 64.

Cât timp durează pentru a învârti întregul ciclu cu toate diodele este de puțin interes pentru noi aici, deoarece este clar că la o puritate de 1 MHz (acolo funcționează MK-ul meu), va fi suficient de rapid pentru ca ochiul să nu poată vezi orice pâlpâire.

Foto asamblare:


click pe fotografie pentru a mari

Și iată un videoclip al lucrării: (avi, divx, 3MB)
Videoclipul nu arată bine procesul de tranziție a luminozității, deoarece matricea camerei nu are aceeași inerție vizuală ca ochiul uman, dar, în general, procesul este vizibil.