Come creare un controller PWM con Arduino

La cosiddetta “modulazione dell’ampiezza dell’impulso” (PWM, in sigla) , dove per ampiezza si intende la durata dell’impulso, è una tecnica in cui variamo appunto la durata di un impulso a onda quadra per controllare la potenza fornita a qualsiasi dispositivo collegato. Usando questa tecnica, possiamo simulare un’uscita analogica usando un’uscita digitale. I microcontrollori Arduino, tuttavia, sono già forniti di uscite PWM, facilitandoci quindi il compito. Ecco come realizzare un controller PWM, utile per il controllo attivo di un motore – o di qualche altro tipo di dispositivo o sistema – usando Arduino.

Un’onda quadra è ottenuta con una successione di On (digital high) e Off (digital low), le uniche due opzioni a nostra disposizione se abbiamo un segnale digitale. Quindi, come possiamo ottenere l’intera gamma di valori analogici discreti usando qualcosa di digitale che può avere solo due valori (Alto e Basso)? Usando il tempo per il quale un impulso è ALTO e BASSO, raggiungeremo il risultato desiderato. Dobbiamo però conoscere due parametri di un segnale PWM: il duty cycle e la frequenza.

Ne abbiamo già parlato nel nostro articolo Come regolare la potenza per un carico DC o AC, che trovi qui. Un “ciclo di lavoro” (duty cycle, in inglese), noto anche come ciclo di potenza, rappresenta la frazione di un periodo in un segnale attivo. Ecco cosa significa un ciclo di lavoro in termini semplici. Il duty cycle è la percentuale del rapporto tra l’ampiezza dell’impulso (sempre nel senso di durata) del segnale e il periodo totale (T). Ecco una formula per semplificare ulteriormente le cose:

Illustrazione grafica di cosa è il duty cycle, o ciclo di lavoro, di un PWM.

Ad esempio, se un impulso con un periodo di 20 ms rimane ON (alto) per 4ms, il suo ciclo di lavoro sarà: Duty cycle (D) = 4ms / 20ms = 20%. Il PWM ci aiuta a controllare la potenza erogata al carico utilizzando 0 e 1 come segnale di accensione e spegnimento. Pertanto, possiamo usarlo per controllare la velocità di rotazione del motore e anche l’intensità di un LED, per fare due esempi banali. Ma si potrebbe in linea di principio usare anche per regolare una resistenza scaldante in modo attivo.

Se vogliamo creare un segnale analogico da 2 V che può essere alto (acceso) a 5 V o basso (spento) a 0 V, possiamo usare PWM con un duty cycle del 40%. Fornirà 5 V in uscita per il 40% delle volte. Se il segnale digitale viene ciclicato abbastanza velocemente, la tensione vista in uscita sembra essere la tensione media. Se il minimo digitale è 0 V (che di solito è il caso), la tensione media può essere calcolata prendendo la tensione digitale “alta” moltiplicata per il ciclo di lavoro, o 5 V x 0,4 = 2 V.

Varie tensioni medie ottenibili in uscita con diversi valori del duty cycle. 

La frequenza, invece, è definita come il numero di oscillazioni o occorrenze di un’onda ripetuta per unità di tempo. Il periodo è la durata del tempo di un ciclo completo. Pertanto il periodo è il reciproco della frequenza. Possiamo calcolare la frequenza usando la seguente formula: Frequenza = 1 / Periodo. Per quanto riguarda il PWM, la frequenza degli impulsi si riferisce a quanto velocemente / lentamente, possiamo ottenere l’impulso al dispositivo di uscita. Facciamo un esempio.

Se sto usando un PWM per illuminare le luci a LED e voglio luci soffuse e lente – un po’ come quelle che si accendono molto lentamente e che le persone usano per appuntamenti romantici – la frequenza del treno di impulsi inviati per illuminare il LED dovrà essere bassa. Ma per mantenere la luce costantemente accesa o lampeggiare più velocemente come una luce per ambulanza devo aumentare la frequenza, e si accenderà e spegnerà così rapidamente che sembrerà essere continua sull’occhio umano.

Un esempio di uscita PWM di Arduino con duty cycle del 25%, corrispondente a una tensione media di 1,25 V.

Ora potresti chiedere: se volevo un LED sempre acceso, perché non posso usare un’uscita normale? E se questa è la domanda che ti viene in mente, allora mi complimento per la tua concentrazione. La risposta è: con un PWM, posso anche controllare la luminosità alla quale voglio che siano le luci. Con l’uscita digitale, sono bloccato tra due livelli di luminosità: 0 o 1. Con l’opzione analogica “simulata” realizzata tramite la tecnica PWM, ho più opzioni in termini di controllo della luminosità.

Quindi per riassumere: Ciclo di lavoro: utilizzato per controllare quanta energia viene inviata attraverso il dispositivo; Frequenza: utilizzata per controllare la velocità con cui viene inviata questa potenza. Le applicazioni del PWM, invece, sono innumerevoli, ad esempio:

  • Regolazione della tensione
  • Regolazione della luminosità
  • Controllo della velocità di un motore DC
  • Controllo del calore generato
  • Generazione di segnali audio

Uso basico del PWM con il microcontroller Arduino

Ci sono sei piedini (pin) PWM in Arduino Uno. Ricordo che Arduino Uno ha canali PWM a 8 bit. Questi pin PWM sono rappresentati dal simbolo “~”. Quel simbolo ci dice che questi pin hanno il supporto PWM. I pin PWM di Arduino Uno sono 3,5,6,9,10 e 11. Su questi pin PWM, il duty cycle dell’impulso PWM, che ha una frequenza di 490 Hz (ma di 980 Hz sui pin 5 e 6), è controllato dalla funzione “analogWrite” nel codice (sketch). Pertanto, il periodo corrispondente è di 2 ms per la frequenza di 500 Hz.

I pin PWM su una comune scheda Arduino: la Arduino Uno. 

Sulla maggior parte delle schede Arduino (quelle con ATmega168 o ATmega328), la funzione PWM funziona sui pin 3, 5, 6, 9, 10 e 11. Sulla Arduino Mega, invece, funziona sui pin 2-13 e 44-46. La Arduino Due supporta analogWrite () sui pin da 2 a 13 e sui pin DAC0 e DAC1. A differenza dei pin PWM, il DAC0 e DAC1 sono convertitori da digitale ad analogico e fungono da vere uscite analogiche. Infine, non è necessario chiamare pinMode () per impostare il pin come uscita prima di chiamare analogWrite ().

Si noti che l’Arduino Uno o Mega non hanno un convertitore digitale-analogico (DAC) incorporato. I “segnali analogici” che forniscono sono, in realtà, segnali digitali modulati in larghezza di impulso. È possibile usare la già citata funzione integrata, analogWrite (pin, valore), per fornire un segnale di uscita PWM. Essa ha due argomenti: sono il pin di uscita PWM e l’altro è il valore proporzionale al duty cycle del segnale. Il segnale è OFF quando la variabile “valore” di analogWrite è 0 ed è ON quando essa è 255.

La tensione efficace è più bassa di quella dell’impulso PWM.

Ricorda che il secondo input per analogWrite è un valore a 8 bit, perciò può arrivare al massimo a 255. Ma come si sceglie, in pratica, il relativo valore? Semplice. La tensione di uscita digitale di un Arduino Uno (o Arduino Mega) è 0 V o 5 V. Pertanto, il livello di uscita PWM specificato con analogWrite è un valore a 8 bit che corrisponde a una gamma di tensione effettiva compresa tra 0 e 5 V. Perciò, per fornire ad es. una tensione effettiva di 3 V, occorre porre valore =  (255 / 5 V) x 3 V = 153.

Dunque, una semplice applicazione del PWM è la generazione di un’onda quadra da osservare ad esempio su un economico oscilloscopio digitale USB, che con Arduino Uno sarà di 490 Hz sui piedini 3,9,10 e 11 o di 980 Hz, cioè quasi 1 kHz, sui piedini 5 e 6. Il duty cycle di un’onda quadra è sempre del 50%; pertanto, se vogliamo un’onda quadra sul piedino 5, basterà usare il comando “analogWrite (5, 128)”. Puoi scaricare da qui il relativo codice (sketch) da usare su Arduino Uno per implementare ciò.

L’onda quadra prodotta da Arduino osservata su un economico oscilloscopio digitale USB. Ne puoi trovare diversi, ad esempio, qui.

La funzione “AnalogRead (pin)” di Arduino non richiede alcun file di intestazione speciale. A differenza della funzione analogWrite, legge il valore dal PIN dichiarato. Arduino UNO contiene un convertitore da analogico a digitale (ADC) a 10 bit. Pertanto, può rappresentare il valore che mapperà le tensioni di ingresso tra 0 e la tensione operativa che può essere 5 V o 3,3 V e lo converte in valori interi che vanno tra 0 e 1023. Arduino Uno ha quindi una risoluzione di 5 V / 1024 unità, cioè di 4,9 mV per unità.

Come classico esempio di base dell’applicazione del PWM di Arduino per comandare qualcosa (in particolare, un carico che assorbe pochissimo), possiamo controllare la luminosità di un LED usando un potenziometro, oppure via software. Nel primo caso, è possibile utilizzare la funzione analogRead () per leggere una tensione e la funzione analogWrite () per fornire all’uscita un segnale PWM. Ciò che serve per realizzare questo progetto, in pratica è il seguente materiale:

  • Potenziometro (quello che avete, oppure 50 kohm)
  • Resistenza da 330 ohm
  • Arduino Uno R3
  • Breadboard
  • Cavi jumper

Il circuito da realizzare per il controllo di un led via PWM con Arduino Uno.

Una volta realizzate le connessioni mostrate nella figura, è possibile ruotare il potenziometro, che cambierà la tensione sul pin A0. Usando lo sketch che trovi qui, puoi modificare proporzionalmente il duty cycle del segnale PWM sul pin 3 digitale, che regolerà la luminosità del LED. Senza un potenziometro, puoi ancora collegare un LED con il pin 3 digitale. In questo caso, per modificare la luminosità del LED, un altro sketch che trovi qui modifica il duty cycle dell’uscita del segnale PWM sul pin 3 di Arduino.

Analogamente, potete controllare il volume del suono prodotto da un buzzer con circuiti e sketch praticamente uguali a quelli appena illustrati. L’unica differenza è che il buzzer non necessita della resistenza da 330 ohm in serie, quindi il circuito è ancora più semplice. Inoltre, se pilotiamo il buzzer con il piedino 3 della Arduino Uno (che opera a 490 Hz) otterremo un suono più grave, se invece usiamo il piedino 5 o 6 (che operano a circa 1 kHz), il suono prodotto sarà più acuto.

Lo spettro in frequenza normale, ottenuto con Visual Analyser, di un buzzer (in alto) alimentato a 5 V DC e (in basso) quello dello stesso buzzer alimentato con un PWM a 490 Hz e duty cycle del 50%. Il suono prodotto, nel secondo caso, è più debole e più grave.

Come controllare la frequenza PWM con Arduino

La funzione analogWrite, come abbiamo visto, fornisce una semplice interfaccia all’hardware PWM di Arduino, ma non fornisce alcun controllo sulla frequenza, che può essere solo uno dei valori illustrati in precedenza: 490 o 980 Hz. Probabilmente, per il 90% degli impieghi ci si potrebbe fermare qui e usare solo analogWrite, ma ci sono altre opzioni che offrono maggiore flessibilità nell’uso del PWM con Arduino, e che possono risultare utili quando vogliamo scegliere (o variare) la frequenza del PWM.

Ad esempio, è possibile implementare “manualmente” il PWM su qualsiasi pin di uscita digitale attivando e disattivando ripetutamente il pin per i tempi desiderati. La figura qui sotto mostra il codice che possiamo usare per creare “a mano” un PWM con un duty cycle del 10% e una frequenza di circa 1 kHz. Puoi scaricarlo da qui. Naturalmente, non è difficile adattare lo sketch in modo da produrre un duty cycle o una frequenza diversi agendo sul valore assoluto e sul rapporto fra i ritardi (delay).

Questa tecnica ha il vantaggio di poter utilizzare qualsiasi pin di uscita digitale di Arduino. Inoltre, hai il pieno controllo del ciclo di lavoro (duty cycle) e della frequenza. Uno svantaggio principale è che eventuali interruzioni influiranno sul tempo, il che può causare un notevole jitter, a meno che non si disabilitino gli interrupt. In questo senso, non è il modo preferibile di implementare il PWM ma, se abbiamo necessità di scegliere la frequenza oppure i piedini PWM sono già tutti usati, allora è utile.

Un secondo svantaggio di questa tecnica è che non è possibile lasciare l’output in esecuzione mentre il processore di Arduino fa qualcos’altro, quindi occorre usare un microprocessore praticamente dedicato a questo scopo. Infine, è difficile determinare le costanti appropriate per un determinato duty cycle e frequenza, a meno che non facciano attentamente i relativi calcoli (aiutandoci con un foglio di calcolo come Excel) o si modifichino i valori mentre si guarda l’uscita con un oscilloscopio.

Schema del collegamento diretto di un carico “leggero” a un controller PWM, Arduino o commerciale.

Vi sono poi anche tecniche più avanzate. Il chip ATmega168P / 328P di Arduino ha tre timer PWM, che controllano 6 uscite PWM. Manipolando direttamente i registri del timer del chip, è possibile ottenere un controllo maggiore di quello fornito dalla funzione analogWrite. Il datasheet dell’AVR ATmega328P fornisce una descrizione dettagliata dei timer PWM, ma il datasheet può essere difficile da capire per il dilettante medio, a causa delle diverse modalità di controllo e uscita dei timer.

Pertanto, se vuoi un PWM con frequenza regolabile in modo affidabile ed entro un ampio intervallo di frequenze, puoi usare un generatore PWM commerciale operante a bassa tensione, come ad es. quello in figura, che puoi trovare qui. Esso permette di regolare la frequenza portante da 1 Hz a 150 kHz. Anche se in generale non puoi usarlo direttamente per collegarci dei carichi DC che assorbono più di 5-30 mA (ma esistono modelli che erogano fino a 8A), puoi collegarceli indirettamente, come spiegato nella prossima e ultima sezione di questo articolo.

Un modulo generatore di segnale PWM stand-alone, che può avere numerose applicazioni, specie se si hanno esigenze particolari riguardo la frequenza portante. Lo puoi trovare in vendita qui.

Come controllare grandi carichi AC o DC con il PWM

Ogni pin di uscita digitale di un Arduino Uno può fornire non più di 40 mA. Per guidare carichi di corrente più elevati, l’uscita PWM può essere utilizzata con un transistor che commuta il carico. Questa strategia funziona con piccoli motori a corrente continua (DC). Ad esempio, un transistor 2N2222 ha un limite di corrente di 800 mA, 20 volte superiore a un pin digitale di un Arduino. Un MOSFET (Metal Oxide Field Effect Transistor) può essere usato per controllare carichi DC a correnti più elevate.

Il controllo di carichi in corrente alternata (AC) o anche in continua (DC) ad alta potenza introduce un elevato rischio per lo sperimentatore e non dovrebbe essere tentato senza esperienza sostanziale e abbondanti precauzioni di sicurezza. Pertanto, non illustreremo qui l’uso di Arduino per controllare carichi in AC, ma il lettore troverà facilmente informazioni in merito su Internet. In ogni caso, per molte applicazioni, il controllo di carichi in DC è sufficiente e, fino a circa 60 V, non pericoloso.

Una soluzione per il controllo con Arduino di carichi in alternata (AC) resistivi è un prodotto chiamato PowerSwitchTail, che è disponibile su Internet in versione USA (110 V) o UE (23 V). Esso può controllare dei carichi a 230 V AC grazie a un relè, che può commutare carichi resistivi fino a 15 A, come lampadine, riscaldatori, piccola caldaia, domotica, etc. Un indicatore LED posto sulla scatola indica lo stato del relè. Il dispositivo è optoisolato e controllabile con un singolo pin logico del tuo microcontroller.

Il modulo PowerSwitchTail per il controllo in sicurezza di carichi AC con Arduino. Ovviamente, la scatola deve essere ben chiusa quando è sotto tensione.

Qui ora vedremo invece un circuito elettrico per l’utilizzo del PWM per controllare la velocità di un motore DC. Per un motore DC, l’accumulo di energia negli avvolgimenti del motore attenua efficacemente le “esplosioni” di energia erogate dall’ingresso PWM ad impulsi, in modo che il motore subisca una fornitura di potenza elettrica minore o maggiore a seconda delle larghezze degli impulsi. Oltre al problema della corrente, l’Arduino non può guidare i motori in entrambe le direzioni.

Pertanto, queste carenze vengono risolte utilizzando Arduino per controllare un controller di motore H-bridge come l’L298N. Ma se vogliamo semplicemente regolare la velocità del motore in una sola direzione, possiamo usare lo schema illustrato qui sotto, che prevede l’impiego di un transistor NPN oltre al motore DC e ad un potenziometro. Come nel caso del led, il potenziometro ne regola la velocità. Puoi fare il copia e incolla del relativo semplice codice (sketch) da caricare su Arduino da qui.

Schema del circuito per controllare un motore DC con il PWM e (sotto) implementazione pratica semplificata con i vari collegamenti (la resistenza fissa e il condensatore non sono stati usati).

Il principio di funzionamento e il programma di questo circuito sono gli stessi del controllo della luminosità del LED. L’unica differenza è che e nel circuito è incluso un circuito “di pilotaggio” aggiuntivo che usa un transistor, ad es. un 2N2222 se la corrente assorbita dal motore è abbastanza inferiore a 800 mA (tienilo a mente quando li scegli). Il condensatore C1 by-passa i picchi di tensione e rumori prodotti dal motore. Questo condensatore di filtro è molto essenziale e se non è presente il circuito potrebbe non funzionare correttamente. Ma ora torniamo al controller di motore H-bridge L298N.

Con questo controller, i motori sono collegati ai pin di uscita per motore sui pin 1 e 2 e 13 e 14 dell’L298N, secondo lo schema seguente. I pin 7 e 12 {Enable 1 e Enable 2) vengono utilizzati per controllare la velocità del motore. Possono essere ponticellati a 5 V affinché i motori funzionino sempre alla massima velocità oppure possono essere collegati ai pin di uscita della modulazione di larghezza di impulso (PWM) sull’Arduino (pin 3,5,6,9,10 e 11) che sono contrassegnati da una tilde (~).

Il controller di motore H-bridge L298N, con i relativi piedini.

La velocità del motore DC (da non confondere con quelli passo-passo) viene controllata impostando un valore di analogWrite compreso tra 0 e 255 sul pin di abilitazione selezionato. Se i tuoi sensori creano valori al di fuori di questo intervallo, usa la funzione “map”o “constrain” per farli emergere nel modo giusto. La direzione del motore è invece controllata dai segnali logici digitali forniti dall’Arduino ai pin 8 e 9 (IN1 e IN2) e ai pin 10 e 11 (IN3 e IN4). Se il livello logico di 8 = 9 o 10 = 11, i motori si fermano.

Ecco le funzioni dei vari piedini del controller mostrsato nella figura precedente:

  1. Motore DC 1 “+” o motore passo-passo A +
  2. Motore DC 1 “-” o motore passo-passo A-
  3. Ponticello 12V – rimuovere questo se si utilizza una tensione di alimentazione superiore a 12V DC. Ciò consente l’alimentazione del regolatore 5V di bordo
  4. Collega qui la tensione di alimentazione del motore, massimo 35 V DC. Rimuovi il ponticello da 12 V se> 12 V DC
  5. GND
  6. Uscita 5 V con jumper 12V in posizione, ideale per alimentare il tuo Arduino (ecc.)
  7. Jumper motore DC 1. Lasciarlo in posizione quando si utilizza un motore passo-passo. Collegare all’uscita PWM per il controllo della velocità del motore DC.
  8. IN 1
  9. IN 2
  10. IN3
  11. IN4
  12. Jumper motore DC 2. Lasciarlo in posizione quando si utilizza un motore passo-passo. Collegare all’uscita PWM per il controllo della velocità del motore DC.
  13. Motore CC 2 “+” o motore passo-passo B +
  14. Motore CC 2 “-” o motore passo-passo B-

Collegamento del controller L298N a due motori e ad Arduino Uno.

Come sappiamo, l’Arduino non può emettere una vera tensione analogica, cioè una tensione che varia continuamente da 0 volt a 5 volt. Invece, usando la funzione analogWrite (pin #, val), dove val varia da 0 a 255, emette sul pin # un segnale ad onda quadra di ciclo di lavoro variabile, da 0 a 100%, che varia continuamente la potenza inviata al motore. Puoi scaricare un codice (sketch) per testare i motori destro e sinistro mostrati nello schema qui sopra facendo un copia e incolla da qui su Arduino.