GUIDA ARDUINO 10: LE USCITE PWM

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!!!



 

[Voti Totali: 0 Media Voti: 0]
Segui la Nostra Pagina Facebook: Facebook

2 pensieri su “GUIDA ARDUINO 10: LE USCITE PWM

  1. Articolo molto utile per capire il funzionamento del PWM con Arduino e le funzioni di librerie che lo gestiscono

  2. 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!

Rispondi a Giorgio NICOLUSSI Annulla risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *