Frequenza 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:

Duty Cycle arduino

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 sul’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:

Pin digitali e analogici frequenza pwm

ma non tutte lavorano alla stessa frequenza.

Incuriosito ho voluto approfondire questa informazione e partendo dal sito ufficiale ho trovato questa decrizione.

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:

Frequenza PWM arduino pin

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:

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

Tutte queste informazioni le ho apprese su molti siti che ho sfogliato e letto prima di capire come funzionassero i Timer e i prescaler, ma un ringraziamento speciale voglio rivolgerlo ad un blogger che ha scritto un articolo davvero interessante e ben fatto: settorezero.

Buona sperimentazione !!!

Prima di inserire un commento, per favore, leggi il regolamento

Permanent link to this article: https://www.mauroalfieri.it/elettronica/frequenza-pwm-arduino-duty-cycle.html

40 pings

Skip to comment form

  1. […] DSO leggendo il segnale PWM generato con Arduino. Qualche mese fa ho pubblicato questo articolo: Frequenza PWM su Arduino e Duty Cycle in cui hai letto come funzionano i Timer arduino e come siano connessi ai pin arduino. In […]

  2. […] PWM di arduino, operazione pericolosa che trovi descritta in un mio articolo di qualche tempo fa: Frequenza PWM su Arduino e Duty Cycle che nello sketch di Patrick rappresenta l’unica parte più complessa e le trovi alle linee […]

Lascia un commento

Your email address will not be published.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.