Arduino è in grado di gestire segnali PWM attraverso le sue uscite digitali, ma è anche in grado di regolare la frequenza pwm di tali pin:
In molti articoli ho utilizzato e descritto i segnali PWM e come utilizzarli parlando spesso di Duty Cycle ossia del ciclo di lavoro in cui hai uno stato attivo ( HIGH ) all’interno di un periodo ti tempo stabilito.
Ti invito a leggere l’introduzione sull’argomento in questo articolo.
Qualche giorno fa ho letto che la frequenza di lavoro dei pin PWM su Arduino non è la medesima per tutti i pin.
Prendi ad esempio l’Arduino Uno ( o qualsiasi altro Arduino basato sull’Atmega328 ) sono presenti 6 uscite, che puoi individuare grazie al simbolo ~, utilizzabili come PWM:
ma non tutte lavorano alla stessa frequenza.
In pratica arduino dispone di tre timer distinti definiti Timer0, Timer1 e Timer2 gestiti dall’Atmega328 a ciascun Timer sono collegati 2 comparatori ( Output Compare – OC ) definiti OCxA e OCxB, in cui x vale 0,1 e 2 ciascun numero corrisponde ad uno dei timer, ad ogni comparatore è collegato un pin arduino, ed ecco i 6 pin PWM:
Guardando la tabella noti innanzitutto che i 3 timer sono riportati con la disitura TCCRx in cui x vale 0,1 e 2 e che il Timer0 ha una Frequenza doppia rispetto agli altri due che si ripercuote alla fine della tabella sulla Frequanza PWM di Default in cui la Frequenza PWM dei pin 5 e 6 è doppia rispetto a quella dei pin 3,9,10 e 11.
Differenza di Frequenza PWM
La differenza di Frequenza PWM tra la coppia di pin 5 e 6 e gli altri ti porta a fare delle considerazioni:
- se vuoi collegare due motori o servo motori da controllare in PWM scegli i pin con frequenza uguale;
- la frequenza pwm di default è alquanto bassa;
se consideri che la frequenza PWM del Timer è ad esempio 31250Hz come è possibile che la Frequenza PWM di default sia di soli 488Hz?
La risposta è nel fatto che ciascun Timer ( TCCRx ) possiede due registri denominati A e B, rispettivamente per il Timer0 sono TCCR0A e TCCR0B il cui compito è definire le modalità di funzionamento e altri parametri dei Timer stessi. In particolare il Registo B ( TCCR0B, TCCR1B, TCCR2B ) ha anche il compito di impostare un prescaler che puoi immaginare come una sorta di dividendo della frequenza PWM.
I prescaler sono 5 per i pin connessi ai Timer 0 ed 1: 1,8,64,256,1024 e 7 per il Timer2: 1,8,32,64,128,256,1024 ed il valore di prescaler di default è 64 per tutti i Timer da cui:
31250Hz / 64 = 488Hz
62500Hz / 64 = 976Hz
Modificando quindi il prescaler di un Timer puoi variare la Frequenza PWM dei pin collegati ad esso.
Ricorda che la frequenza non è il Duty Cycle, variando la frequenza PWM otterrai un periodo inferiore ma non un duty cycle differente.
In questo modo la variazione del Timer 1 connesso ai pin 9 e 10 ti permette di continuare a impostare il duty cycle differente sui due pin con il comando analogWrite( pin, val );
Il Timer0 di Arduino
Il Timer0, a cui sono collegati i pin 5 e 6, è collegato anche alle funzioni di ritardo interne al micro controllore come ad esempio delay() e millis() ed è riferimento per la classe Servo ed altre librerie che sfruttano il Timer dell’Atmega328/168.
E’ quindi sconsigliato l’uso di questo Timer a frequenza differenti da quelle impostate dal costruttore per evitare comportamenti imprevisti delle funzioni citate.
Modificare la frequanza PWM
Hai visto che è possibile modificare la Frequenza PWM variando il prescaler dell’Output compare corrispondente ad un pin, per farlo è disponibile sul playground arduino questa semplice funzione:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
void setPwmFrequency( int pin, int divisor) { byte mode; if (pin == 5 || pin == 6 || pin == 9 || pin == 10) { switch (divisor) { case 1: mode = 0x01; break ; case 8: mode = 0x02; break ; case 64: mode = 0x03; break ; case 256: mode = 0x04; break ; case 1024: mode = 0x05; break ; default : return ; } if (pin == 5 || pin == 6) { TCCR0B = TCCR0B & 0b11111000 | mode; } else { TCCR1B = TCCR1B & 0b11111000 | mode; } } else if (pin == 3 || pin == 11) { switch (divisor) { case 1: mode = 0x01; break ; case 8: mode = 0x02; break ; case 32: mode = 0x03; break ; case 64: mode = 0x04; break ; case 128: mode = 0x05; break ; case 256: mode = 0x06; break ; case 1024: mode = 0x7; break ; default : return ; } TCCR2B = TCCR2B & 0b11111000 | mode; } } |
in cui i pin 5,6,9,10 accettano solo cinque valori di prescaler che puoi impostare, mentre i pin 3 e 11 accettano anche tagli di prescaler a 32 e 128.
La funzione presentata puoi utilizzarla con la seguente sintassi:
setPwmFrequency(3, 8); |
in cui il primo parametro rappresenta il pin su cui vuoi impostare il prescaler ed il secondo parametro è il prescaler da impostare.
Nell’esempio il pin su cui andrai a modificare la frequenza PWM è il pin 3, collegato a OC2B e Timer TCCR2 e la frequanza PWM impostata sarà:
31250Hz / 8 = 3904Hz = 3,9KHz
Buona sperimentazione !!!
Auto Amazon Links: Auto Amazon Links The Associate tag is not set. Please check your unit settings.
Auto Amazon Links: No products found.
Grazie.