
Arduino, essendo basato sul core Atmega328, supporta nativamente la periferica di modulazione PWM utile in tutte le situazioni in cui si cerca di emulare, con un microcontrollore, la variazione continua di una grandezza, tipicamente una tensione.
Associando alla variazione di tensione la variazione di una qualunque altra grandezza fisica (adoperando dei trasduttori), con la modulazione PWM si può ottenere il controllo della stessa con un’accuratezza che dipende dal numero di bit con i quali, all’interno del micro, è possibile fissare il duty-cycle. Non mi dilungo ulteriormente sulla teoria della modulazione PWM ma mi accingo ad illustrare due possibili tecniche firmware che permettono, con differente difficoltà e richiesta di dettaglio dell’architettura, di utilizzare la tecnica PWM su Arduino.
Modulazione PWM versione semplice: analogWrite().
La tecnica più semplice per gestire una modulazione PWM tramite Arduino consiste nell’avvalersi della funzione analogWrite(pin, dutyCycle) dove il parametro dutyCycle è un valore intero compreso tra 0 e 255 (risoluzione a 8bit). Attenzione perché il nome della funzione è forviante, l’uscita del pin indicato come primo parametro è in realtà digitale.
La funzione analogWrite() regola la larghezza dell’impulso dello stato on rispetto al periodo dell’onda ma non permette nessun controllo sulla frequenza, motivo questo per transitare verso una tecnica un po’ più prolissa ma altrettanto efficace e flessibile.
Uso diretto dei registri dell’Atmega328.
Faccio riferimento all’Atmega328 perché è il core delle versioni di Arduino più diffuse in circolazione (10000, 2009 e UNO), anche sa valgono i medesimi discorsi per l’Atmega168.
Per il controllo della periferica PWM, l’Atmega328 dispone di tre timer ognuno dei quali regola le tempistiche di 2 uscite PWM col risultato di poter contare su massimo 6 canali, configurabili per lavorare in modo indipendente o in coppia e complementati. Sul datasheet del componente, ovviamente, è possibile recuperare tutti i dettagli riguardanti la configurazione dei registri attinenti alle varie periferiche e nel caso specifico alla periferica PWM.
Per evitare particolari perdite di tempo a chi tempo non ha o non è così avvezzo alla lettura dei datasheet (usa Arduino anche colui che nulla sa di elettronica ma che riesce in breve tempo a mettere insieme le funzioni di libreria vedendo funzionare la propria applicazione il successo di Arduino, se vogliamo è anche e soprattutto questo!!) riporto di seguito un minimo di teoria e l’implementazione della tecnica fast PWM.
FastPWM: un minimo di sana teoria!!
In virtù di quanto detto nella breve premessa fatta sopra,i timer dedicati al funzionamento della periferica PWM sono tre e vanno sotto il nome di Timer 0, Timer 1, e Timer 2. Ad ogni timer sono associati due registri con i quali viene confrontato il valore di conteggio, potendo regolare di conseguenza la larghezza dell’impulso PWM. Ad ogni comparatore è associata un’uscita che va alta a seconda del risultato della comparazione, quindi ad ogni comparatore è associata un’uscita PWM, e quindi ancora ad ogni Timer sono associate due uscite PWM.
Ad ogni timer è associabile un fattore di prescaler (divisione in frequenza) tra i possibili che si possono impostare: 1, 8, 64, 256 o 1024. Arduino ha un clock di sistema di 16MHz e la frequenza di clock dei vari timer PWM (un clock uguale per tutti i timer) è pari alla frequenza di sistema diviso il fattore di prescaler. L’unico a disporre di un fattore di prescaler differente dagli altri timer è il Timer 2, potendo quindi impostare una frequenza di PWM differente dalla frequenza dei restanti 4 canali (ricordando che ad ogni timer si fanno corrispondere due canali PWM).
I timer possono inoltre lavorare in diverse modalità, e le principali sono la “Fast PWM” e la “PWM con correzione di fase”. Inoltre per i timer si può decidere di far fare loro il conteggio da 0 a 255 (risoluzione PWM di 8bit) oppure da 0 ad un valore fissato (minore di 255) al fine di aumentare la frequenza PWM pur rinunciando a qualcosa in termine di risoluzione sull’impostazione della larghezza di impulso. Solo al timer 1 è associata la possibilità di estendere la risoluzione da 8 a 16 bit riducendo però sensibilmente la frequenza di clock. Ogni uscita può essere inoltre invertita.
Giusto per completezza, ogni timer può generare un segnale di interrupt di overflow o di matching ma questo approfondimento non serve ai fini della semplice generazione della modulazione PWM.
Dettaglio sui registri.
Ogni timer associato a due canali PWM ha a disposizione i registri di configurazione TCCRnA e TCCRnB, dove la lettera n generalizza il numero del timer corrispondente (n=0 per il Timer 0, n=1 per il Timer 1, ecc…). Di questi registri sono essenziali i seguenti bit di configurazione:
- I bit WGM (Waveform Generation Control) che configurano il timer nelle diverse modalità di funzionamento;
- I bit CS (Clock Select) controllano il fattore di prescaler associato al clock;
- COMnA: bit che permettono di attivare, disattivare e invertire l’output A;
- COMnB: bit che permettono di attivare, disattivare e invertire l’output B.
- I registri OCRnA e OCRnB settano i livelli di comparazione delle due uscite, A e B e quindi i corrispettivi duty-cycle.
Fast PWM
Nella modalità fast più semplice, i timer contano ciclicamente da 0 a 255. L’uscita va alta quando il timer è 0 mentre va bassa quando il timer raggiunge il valore contenuto nel registro di comparazione. Più alto è il valore del registro, maggiore è il duty-cycle. La figura che segue mostra l’andamento dei registri OCRnA e OCRnB. Entrambe le uscite hanno la stessa frequenza di PWM.
Per attuare efficacemente la Fast PWM, di seguito riporto uno esempio di codice già funzionante che, sfruttando il timer2, genera sul pin 3 di Arduino2009 un’onda quadra a duty-cycle variabile a frequenza 100kHz (spesso eccessiva per applicazioni switching di potenza, però è giusto per dare un esempio di fin dove ci si riesce a spingere con questa tecnica).
Prima dell’esempio, riporto una piccolissima nota circa il controllo della frequenza attraverso l’utilizzo del livello alto di comparazione OCRnA.
Come si è detto in precedenza, è possibile far contare il singolo timer da 0 a 255 come di default oppure da 0 a ad un valore fissato in modo da aumentare la frequenza pur perdendo qualcosa sulla risoluzione PWM. Per il Timer2, agendo sul registro TCCR2A, è possibile far contare il Timer2 fino al valore contenuto nel registro OCR2A. Naturalmente, questo valore non può più essere utilizzato per regolare in PWM l’uscita OC2A. Esiste però un’opzione ulteriore che permette di fare il toggle dell’uscita OC2A tutte le volte che il timer attraversa la soglia, quindi disponendo di un’onda quadra a duty cycle fisso al 50% e con frequenza pari alla metà della frequenza PWM dell’altro canale.
La frequenza del segnale PWM può essere calcolata con la seguente formula:
f=f_clk/(prescaler*OF_Value)=16MHz/(prescaler*OverFlow_value).
Esempio applicativo.
int variabile=0; static char mode=0; void setup() { // Configurazione del Timer2 per funzionare in modo fast PWM su OC2B (pin 3 di Arduino) // set pin high on overflow, clear on compare match with OCR2B TCCR2A = 0x23; // imposto “pin high on overflow”, e “clear on compare match with OCR2B TCCR2B = 0x09; // seleziono come sorgente di clock I 16MHz di sistema senza prescaler OCR2A = 159; // inizializzo il top level match a 159 ->f_PWM=100kHz pinMode(3, OUTPUT); // abilito come uscita il pin 3. } void loop() { if(mode==0) { variabile++; if(variabile==160) //controllo che il duty sia arrivato al 100% { mode=1; } } if(mode==1) { variabile--; if(variabile==0) //controllo che il duty sia arrivato a 0% { mode=0; } } OCR2B=variabile; delay(10); }
Il codice presentato fa il fading di un led posto sul pin digitale 3 di Arduino2009, sia in accensione che in spegnimento, ed è la dimostrazione visiva del funzionamento del codice. Variando tra 0 e 159 il contenuto del registro OCR2B si varia il duty-cycle tra 0 e 100%.
Il dettaglio del registro TCCR2A riportato di seguito mostra il perchè dell’inizializzazione dello stesso a 0x23. Infatti, in binario, il valore inizializzato è pari a 00100011 e quindi, i primi due bit meno significativi (WGM21 – WGM20) impostano la modalità di funzionamento Fast_PWM (per le altre modalità rifarsi al datasheet dell’ATmega328) mentre il quarto e il quinto bit partendo sempre dal meno significativo (COM2B1 – COM2B0) indicano come commuta l’uscita OCB2 (uscita 3) (tutte le possibili combinazioni sono riportate nel datasheet)
Per quanto riguarda il registro TCCR2B, questo è inizializzato a 0x09 (00001001 in binario) cioè si va ad indicare la preferenza di non utilizzare nessun fattore di prescaler ma di considerare come sorgente di clock per il timer i 16MHz di sistema (per ulteriori dettagli rifarsi al datasheet).
Chiudo l’articolo dicendo che se si volesse disattivare completamente l’uscita PWM, basta impostare il relativo pin come ingresso in modo da configurarlo in alta impedenza
pinMode(3, INPUT); // abilito come ingresso il pin 3.

Una piccola nota sull’articolo.
Con l’istruzione analogWrite() la frequenza di PWM è fissa e pari a 490Hz, troppo bassa per una moltitudine di applicazioni come il controllo switching dei convertitori di potenza ma anche per la stessa conversione D/A. Infatti, esiste un teorema che afferma che per poter ricostruire un segnale analogico a partire da una modulazion PWM, è necessario che la frequenza portante sia 9 volte la banda del segnale modulante. Preso per buono questo teorema, il massimo che si riuscirebbe a ricostruire con l’istruzione analogWrite è un segnale con banda poco più alta di 49Hz. Questo è il motivo per cui si fa ricorso alle tecniche PWM fast.
La tecnica PWM a correzione di fase, differisce dalla Fast per l’avere una portante triangolare anziché una a dente di sega. Questa porta il vantaggio di sincronizzare le PWM dei vari canali in corrispondenza dei massimi e dei minimi della triangola (i timer conta prima in avanti e poi indietro) facendo in modo che i fronti di salita e discesa delle onde PWM non siamo coincidenti. In un contesto “convertitore di potenza” dove ai vari segnali PWM corrispondono diversi ampere di corrente, la tecnica a controllo di fase può fare la differenza sull’emissioni EM. La frequenza di portante è però pari alla metà rispetto alla fast.
Mi dai il link dell’articolo in inglese, per favore?
Buongiorno,come faccio per parlare in privato?
Ciao, puoi scrivere qua per chiedere informazioni relativamente all’articolo. Grazie 🙂
Grazie,avrei necessita’ di un sistema che rilevi da un primo generatore una potenza elettrica alternata e che per mezzo di impulsi pwm controlli (moduli) un’altro generatore per mantenere il piu basso possibile l’assorbimento dal primo generatore.spero di essere stato abbastanza chiaro nell’esposizione.con arduino sono riuscito a creare un accrocco che piu o meno funziona, tuttavia ho dei problemi con i finali pwm che spesso vanno in corto,vero che gestiscono 3kw ma gli ho sempre sovradimensionati.grazie
Da capire meglio il progetto. Ma forse i finali non sono sufficienti. Ho paura per la scheda, non vorrei che stia “soffrendo”.
Ciao avrei bisogno di aiuto per un problema.grazie
salve sarebbe possibile creare un ritardo sull’esecuzione del valore del potenziometro?
una specie ci proporzionale
grazie