Nella Decima Parte della Guida verrà Illustrato il Funzionamento del PWM e come Inizializzare le Uscite di Questo tipo…
INTRO
Il segnale PWM (pulse width modulation, ovvero modulazione a larghezza di impulso) è un segnale digitale in cui il periodo dell’impulso a livello alto varia rispetto il periodo del segnale. Questo tipo di segnale permette di ottenere un segnale analogico variando il periodo dell’impulso.
Il segnale PWM ha due caratteristiche, l’ampiezza massima e il duty cycle, la prima dipende dal segnale mentre il secondo parametro descrive la durata dell’impulso a livello alto secondo la formula seguente:
Quindi il duty cycle si misura in percentuale ed è dato dal periodo del segnale a livello alto diviso il periodo del segnale moltiplicato per 100. Si può anche esprimere come numero decimale senza moltiplicare per 100. Ad esempio si hanno i seguenti valori:
Nel primo caso il segnale non è mai a livello alto, quindi Ton=0 e di conseguenza il duty cycle è pari a 0. Nel secondo, terzo e quarto esempio si ha rispettivamente un duty cycle del 25%, 50% e 75% perché nel primo caso il Ton è pari a ¼ del periodo T e piano piano cresce. Nell’ultimo esempio il segnale è sempre a livello alto quindi il duty cycle è pari al 100%.
Perché Arduino chiama queste uscite analogiche? In realtà sono uscite digitali perché assumono due soli valori ovvero 5V-0V o in generale un livello alto e un livello basso. Consideriamo l’energia trasportata da un segnale PWM, consideriamo la tensione media del segnale, secondo la formula matematica della tensione media si avrà:
Dalla definizione di tensione media e dalla definizione di duty cycle si ottiene dopo aver risolto l’integrale molto semplice che la tensione media è uguale a VCC moltiplicato per il duty cycle. Il duty cycle può assumere valori da 0 a 1 ottenendo quindi una tensione media che va da un minimo di 0V ad un massimo di VCC.
Ad esempio se ho una tensione VCC=5V e 3 valori di duty cycle, ad esempio 25%, 50% e 75% avrò tre valori medi in uscita ovvero 5*0.25=1.25V, 5*0.5=2.5V e nel caso di duty cycle 75% si avrà 5V*0.75=3.75V. Quindi supponendo di avere un LED con resistore di protezione in uscita (calcolato considerando 5V) è come se alimentassi il LED con 1.25V, 2.5V o 3.75V variando quindi la luminosità del LED. La stessa cosa può essere fatta per ventole, motori DC o altri carichi, l’importante è ricordare che in uscita da Arduino si hanno al massimo 20mA, quindi se collego un motore mi serve un driver oppure un mosfet o transistor. Arduino accende e spegne il transistor o mosfet che a loro volta pilotano il carico.
LA LIBRERIA
Più che una vera e propria libreria, per il controllo delle uscite PWM, vi è una istruzione grazie alla quale è possibile variare il PWM in uscita del pin indicato sempre nella stringa. La stringa è “analogWrite(numero_del_pin, Valore_PWM_da_0_a_255);” e in questa stringa si indica il numero del pin (ad esempio per Arduino Uno i pin PWM sono il 3, 5, 6, 9, 10 e 11) e il valore del duty cycle è espresso da 255 a 0 dove 255 è uguale ad un duty cycle del 100% mentre 0 dello 0%. Quindi il valore del duty cycle è dato da (“valore_PWM”/255)*100.
Ad esempio un codice per variare il duty cycle ogni 2 secondi con valori di 100%, 50%, 75% e 25%, scegliendo come uscita il pin3, è il seguente:
byte valorePWM; //Inizializza una variabile utile void setup(){ pinMode(3, OUTPUT); //Pin 3 uscita (il pin 3 è una uscita PWM) } void loop(){ analogWrite(3, 255); //255 => DC 100% DC=valore/255 pin 3 delay(2000); analogWrite(3, 255/2); //255/2 = 125 => DC 50% DC=valore/255 pin 3 delay(2000); analogWrite(3, 192); //DC = (192/255)*100 = 75% valore = (255/100)*DC pin 3 delay(2000); valorePWM = 63; //Valore = 2.55 * 25 = 63 analogWrite(3, valorePWM); //DC = 25% valore = (255/100)*DC pin delay(2000); }
Vado semplicemente ad inizializzare una variabile ad 8 bit (valore massimo 255) che contiene il valore del PWM da 0 a 255, poi inizializziamo come PWM il pin 3 e poi andiamo a configurare in vari modi il PWM con i valori detti in precedenza.
Per quanto riguarda lo schema, si ha la seguente situazione:
Nel primo caso si va a controllare un LED, connesso direttamente all’uscita 3 con un resistore da 470 Ohm come protezione. Nel secondo caso si suppone di voler alimentare una ventola del PC con il PWM e quindi si ha che la ventola è connessa ai 5V al positivo mentre al negativo ha il collettore di un transistor NPN con emettitore a massa e base connessa al pin 3 con un resistore di protezione da 1kOhm.
In tutti questi casi, nella libreria, non è mai stato impostato il valore di T ovvero la frequenza del segnale PWM, si è indicato solo il valore del duty cycle. In particolare la frequenza è pari a 490Hz per alcune uscite (pin 9, 10, 3 e 11 di Arduino UNO), quindi il valore di T è 2mS e il Ton varia tra 0 e 2ms con una risoluzione di 7us ovvero non posso avere tutti i valori di Ton e quindi duty cycle varia da 0 a 100% con risoluzione di 0.39%. Per le altre uscite (pin 5 e 6 per Arduino UNO) la frequenza è circa 980Hz.
Per aumentare questa frequenza bisogna agire sui registri dell’ATMEGA.
PWM CON ARDUINO UNO E ARDUINO MEGA 2560 E CONFIGURAZIONE REGISTRI
I microcontrollori ATMEGA montati sui moduli ARDUINO hanno 4 modalità di PWM, ognuno con funzionalità diverse. Si ha:
- Fast PWM: permette un PWM a frequenza doppia rispetto alle altre modalità e sfrutta un timer counter che conta da 0 a 255, il valore del duty cycle dipende dal valore memorizzato in un registro e il segnale cambia stato quando il valore di conteggio eguaglia quello del registro.
- Phase correct PWM: permette un PWM a frequenza metà rispetto la modalità Fast però permette di avere risoluzione doppia rispetto al caso precedente. La frequenza dimezzata è dovuta al fatto che il timer counter conta da 0 a 255 e poi da 255 a 0, si ha il cambio del livello in base al fatto che il dato memorizzato nel registro è maggiore o minore del conteggio.
- Frequency and phase correct PWM: simile al secondo caso però con la possibilità di variare la frequenza modificando il valore massimo del conteggio. Si riduce però la risoluzione.
- CTC mode: Simile alla modalità fast però con possibilità di variare la frequenza variando il massimo valore contato.
Considerando il valore del contatore e il valore memorizzato nel registro di comparazione, per i 4 differenti casi si ha:
Nella modalità Fast PWM si ha una frequenza pari a CLK/(N*Top) dove CLK è il clock del microcontrollore che nel caso di Arduino è 16MHz, N è il valore del prescaler settato nei registri e Top invece è il valore massimo del conteggio. Nella modalità Phase correct la formula è CLK/(2*N*Top). Il timer counter può essere a 8bit o 16bit. Per ARDUINO UNO si ha il timer counter 0 e 2 ad 8 bit e il timer counter 1 a 16 bit mentre per ARDUINO MEGA 2560 si ha il timer counter 0 e 2 ad 8bit mentre i timer counter 1, 3 e 4 a 16bit.
Arduino UNO ha 6 uscite PWM ma ha solo 3 timer counter, questo è possibile perché per ogni timer counter si hanno due comparatori e due diversi registri dove immagazzinare il valore del duty cycle. Ovviamente non posso usare due modalità diverse per PWM con timer counter in comune. Si ha il pin 5 e 6 per il timer 0, il pin 9 e 10 per il timer 1 e i pin 3 e 11 per il timer counter 2 in ARDUINO.
Andiamo a vedere ora i registri per il PWM usando il timer counter 0 di ARDUINO UNO. I registri hanno la stessa funzione per tutti i timer counter, cambiano solo i nomi, facilmente reperibili nel datasheet. Si ha:
Il primo registro serve per settare la modalità del segnale di uscita e in particolare si ha:
- COM0A1: COM0A0 [0,0] in questo caso OC0A è scollegato e il PWM non funziona.
- COM0A1: COM0A0 [0,1] non utilizzata.
- COM0A1: COM0A0 [1,0] segnale in uscita alto quando si ha il timer a 0 e poi segnale a 0 quando il timer counter raggiunge il valore memorizzato nel registro.
- COM0A1: COM0A0 [1,1] operazione contraria al caso precedente.
Per i bit COM0B1 e COM0B0 si hanno le stesse funzioni solo che controllano l’uscita del pin 5 mentre i bit precedenti controllano l’uscita del pin 6.
I bit WGM0x invece controllano la modalità del PWM secondo la seguente configurazione:
- WGM02, WGM01, WGM00 [0,0,0] Modalità normale, top=255
- WGM02, WGM01, WGM00 [0,0,1] Phase correct PWM, top=255
- WGM02, WGM01, WGM00 [0,1,0] Modalità CTC, top=registro OCRA
- WGM02, WGM01, WGM00 [0,1,1] Fast PWM, top=255
- WGM02, WGM01, WGM00 [1,0,1] Phase correct PWM, top=registro OCRA
- WGM02, WGM01, WGM00 [1,1,1] Fast PWM, top=registro OCRA
I bit FOC0A e FOC0B non vengono usati mentre i tre bit CS0 servono a selezionare il clock di funzionamento del timer, ovvero il prescaler e si ha:
Si può anche usare un clock esterno connettendo una sorgente di clock al pin T0. Per contenere il valore del duty cycle vi è il registro OCR0A per il pin 6 mentre per il pin 5 vi è il registro OCR0B.
Ad esempio proviamo a scrivere un codice per avere un PWM in modalità fast, con top 255. Considerando che la frequenza del clock interno è 16MHz e supponiamo di volere una frequenza di 8KHz circa serve un prescaler di 8 considerando Fpwm = (16000[KHz])/(255*8) = 7.8KHz.
Il codice è il seguente:
void setup() { pinMode(6, OUTPUT); TCCR0A=0; //resetta il registro TCCR0B=0; //resetta il registro TCCR0A=0b10000011; //Azzera OC0A quando raggiunge il valore, OC0B spento, Fast PWM TCCR0B=0b000000010; //Prescaler 0 } void loop() { OCR0A = 64; //Duty cycle 25% delay(2000); //Attendi 2 secondi OCR0A = 128; //Duty cycle 50% delay(2000); //Attendi 2 secondi OCR0A = 192; //Duty cycle 75% delay(2000); //Attendi 2 secondi }
Quindi il duty cycle sarà per 2 secondi 25%, poi diventa 50% e poi 75%. Lo schema è uguale al caso precedente solo che l’uscita del PWM sarà solo l’uscita del pin 6. Il risultato, analizzato con un oscilloscopio, è il seguente:
Nel caso si usi un timer counter a 16 bit si ha un duty cycle con valore a 16bit.
DOWNLOAD
Potete scaricare la simulazione del circuito con PROTEUS e gli SKETCH al seguente LINK!!!
Articolo molto utile per capire il funzionamento del PWM con Arduino e le funzioni di librerie che lo gestiscono
Suggerito da chatgpt per risolvere un quesito della prova di maturità istituto tecnico industriale x elettronici, ho scoperto un mondo interessantissimo!
Lo userò a scuola!