Modificare la Frequenza del PWM su Arduino e Duty Cycle

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.

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

Grazie.

Lascia un commento

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

Close
Navigation

Categories