Incrementando la frecuencia PWM de Arduino


¿Cuál es el problema?

Como dijimos en la lección sobre funciones de tiempo y sobre la señal PWM, Arduino tiene varios temporizadores que pueden realizar diferentes funciones, en particular, generar una señal PWM. Para que el temporizador genere PWM, primero debe configurarse editando el registro del temporizador. Cuando trabajamos en el IDE de Arduino, los temporizadores se configuran sin nuestro conocimiento en la biblioteca Arduino.h, y de hecho obtienen la configuración que los desarrolladores querían. Y esta configuración no es muy buena: la frecuencia PWM predeterminada es baja, las capacidades de los temporizadores no se utilizan por completo. Veamos el PWM estándar del ATmega328 (Arduino UNO / Nano / Pro Mini):

TemporizadorPinesFrecuenciaResolución
Temporizador 0D5 y D6976 Hz8 bits (0-255)
Temporizador 1D9 y D10488 Hz8 bits (0-255)
Temporizador 2D3 y D11488 Hz8 bits (0-255)
Frecuencia Pwm estándar de arduino

De hecho, todos los temporizadores Arduino pueden emitir de forma segura una señal PWM de 64 kHz, y el temporizador 1 es generalmente de 16 bits, y en la frecuencia que le dio Arduino, podría funcionar con una resolución de 15 bits en lugar de 8, y esto, por un minuto, 32768 gradaciones o ciclos en lugar de 256 !!! Entonces, ¿por qué tanta injusticia? El temporizador 0 está contando el tiempo y está configurado para que los milisegundos se marquen exactamente. Y el resto de los temporizadores simplemente se peinan a cero talla única, para que el maker arduino no tenga problemas innecesarios. Este enfoque es generalmente comprensible, ¿pero hicieron al menos un par de funciones estándar para una frecuencia más alta?, bueno, ¡en serio! De acuerdo, si no lo hicieron ellos, lo haremos nosotros.


Configuración de la frecuencia PWM Arduino a través de registros.

Como comentamos en una lección anterior, Arduino se configura en un nivel bajo a través de los registros, por lo que la generación PWM se configura a través de los registros del temporizador. A continuación, encontrará varias «piezas» de código listas para usar que solo necesita insertar en setup (), y la frecuencia PWM se reconfigurará (el preescaler y el modo de temporizador se cambiarán). Aún puede trabajar con una señal PWM usando la función analogWrite (), controlando el ciclo de PWM en los pines estándar.

Cambio de la frecuencia PWM a ATmega328 (Arduino UNO / Nano / Pro Mini)

Pines D5 y D6 (Timer 0) – 8 bits.

// Pines D5 y D6 - 62,5 kHz
TCCR0B = 0b00000001 ; // x1
TCCR0A = 0b00000011 ; // pwm rápido
// Pines D5 y D6 - 31,4 kHz
TCCR0B = 0b00000001 ; // x1
TCCR0A = 0b00000001 ; // fase correcta
// Pines D5 y D6 - 7.8 kHz
TCCR0B = 0b00000010 ; // x8
TCCR0A = 0b00000011 ; // pwm rápido
// Pines D5 y D6 - 4 kHz
TCCR0B = 0b00000010 ; // x8
TCCR0A = 0b00000001 ; // fase correcta
// Pines D5 y D6 - 976 Hz - predeterminado
TCCR0B = 0b00000011 ; // x64
TCCR0A = 0b00000011 ; // pwm rápido
// Pines D5 y D6 - 490 Hz
TCCR0B = 0b00000011 ; // x64
TCCR0A = 0b00000001 ; // fase correcta
// Pines D5 y D6 - 244 Hz
TCCR0B = 0b00000100 ; // x256
TCCR0A = 0b00000011 ; // pwm rápido
// Pines D5 y D6 - 122 Hz
TCCR0B = 0b00000100 ; // x256
TCCR0A = 0b00000001 ; // fase correcta
// Pines D5 y D6 - 61 Hz
TCCR0B = 0b00000101 ; // x1024
TCCR0A = 0b00000011 ; // pwm rápido
// Pines D5 y D6 - 30 Hz
TCCR0B = 0b00000101 ; // x1024
TCCR0A = 0b00000001 ; // fase correcta

Pines D9 y D10 (Timer 1) – 8 bits.

// Pines D9 y D10 - 62,5 kHz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00001001 ; // x1 pwm rápido
// Pines D9 y D10 - 31,4 kHz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00000001 ; // x1 fase correcta
// Pines D9 y D10 - 7.8 kHz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00001010 ; // x8 pwm rápido
// Pines D9 y D10 - 4 kHz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00000010 ; // fase x8 correcta
// Pines D9 y D10 - 976 Hz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00001011 ; // x64 pwm rápido
// Pines D9 y D10 - 490 Hz - predeterminado
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00000011 ; // fase x64 correcta
// Pines D9 y D10 - 244 Hz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00001100 ; // x256 pwm rápido
// Pines D9 y D10 - 122 Hz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00000100 ; // x256 fase correcta
// Pines D9 y D10 - 61 Hz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00001101 ; // x1024 pwm rápido
// Pines D9 y D10 - 30 Hz
TCCR1A = 0b00000001 ; // 8 bits
TCCR1B = 0b00000101 ; // x1024 fase correcta

Pines D9 y D10 (Timer 1) – 10 bits.

// Pines D9 y D10 - 15,6 kHz 10 bits
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00001001 ; // x1 pwm rápido
// Pines D9 y D10 - 7.8 kHz 10bit
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00000001 ; // x1 fase correcta
// Pines D9 y D10 - 2 kHz 10 bits
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00001010 ; // x8 pwm rápido
// Pines D9 y D10 - 977 Hz 10bit
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00000010 ; // fase x8 correcta
// Pines D9 y D10 - 244 Hz 10 bits
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00001011 ; // x64 pwm rápido
// Pines D9 y D10 - 122 Hz 10bit
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00000011 ; // fase x64 correcta
// Pines D9 y D10 - 61 Hz 10 bits
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00001100 ; // x256 pwm rápido
// Pines D9 y D10 - 30 Hz 10 bits
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00000100 ; // x256 fase correcta
// Pines D9 y D10 - 15 Hz 10 bits
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00001101 ; // x1024 pwm rápido
// Pines D9 y D10 - 7.5 Hz 10bit
TCCR1A = 0b00000011 ; // 10 bits
TCCR1B = 0b00000101 ; // x1024 fase correcta

Pines D3 y D11 (Timer 2) – 8 bits.

// Pines D3 y D11 - 62,5 kHz
TCCR2B = 0b00000001 ; // x1
TCCR2A = 0b00000011 ; // pwm rápido
// Pines D3 y D11 - 31,4 kHz
TCCR2B = 0b00000001 ; // x1
TCCR2A = 0b00000001 ; // fase correcta
// Pines D3 y D11 - 8 kHz
TCCR2B = 0b00000010 ; // x8
TCCR2A = 0b00000011 ; // pwm rápido
// Pines D3 y D11 - 4 kHz
TCCR2B = 0b00000010 ; // x8
TCCR2A = 0b00000001 ; // fase correcta
// Pines D3 y D11 - 2 kHz
TCCR2B = 0b00000011 ; // x32
TCCR2A = 0b00000011 ; // pwm rápido
// Pines D3 y D11 - 980 Hz
TCCR2B = 0b00000011 ; // x32
TCCR2A = 0b00000001 ; // fase correcta
// Pines D3 y D11 - 980 Hz
TCCR2B = 0b00000100 ; // x64
TCCR2A = 0b00000011 ; // pwm rápido
// Pines D3 y D11 - 490 Hz - predeterminado
TCCR2B = 0b00000100 ; // x64
TCCR2A = 0b00000001 ; // fase correcta
// Pines D3 y D11 - 490 Hz
TCCR2B = 0b00000101 ; // x128
TCCR2A = 0b00000011 ; // pwm rápido
// Pines D3 y D11 - 245 Hz
TCCR2B = 0b00000101 ; // x128
TCCR2A = 0b00000001 ; // fase correcta
// Pines D3 y D11 - 245 Hz
TCCR2B = 0b00000110 ; // x256
TCCR2A = 0b00000011 ; // pwm rápido
// Pines D3 y D11 - 122 Hz
TCCR2B = 0b00000110 ; // x256
TCCR2A = 0b00000001 ; // fase correcta
// Pines D3 y D11 - 60 Hz
TCCR2B = 0b00000111 ; // x1024
TCCR2A = 0b00000011 ; // pwm rápido
// Pines D3 y D11 - 30 Hz
TCCR2B = 0b00000111 ; // x1024
TCCR2A = 0b00000001 ; // fase correcta

Ejemplo de uso.

void setup() {
  // Pines D5 y D6 - 7.8 kHz
  TCCR0B = 0b00000010 ; // x8
  TCCR0A = 0b00000011 ; // pwm rápido
  // Pines D3 y D11 - 62,5 kHz
  TCCR2B = 0b00000001 ; // x1
  TCCR2A = 0b00000011 ; // pwm rápido
  // Pines D9 y D10 - 7.8 kHz 10bit
  TCCR1A = 0b00000011 ; // 10 bits
  TCCR1B = 0b00000001 ; // x1 fase correcta
  analogWrite ( 3, 15 ) ;
  analogWrite ( 5, 167 ) ;
  analogWrite ( 6, 241 ) ;
  analogWrite ( 9, 745 ) ;   // sí, rango 0-1023
  analogWrite ( 10, 345 ) ;  // sí, rango 0-1023
  analogWrite ( 11, 78 ) ;
}
void loop() {
}

¡Importante! Si cambia la frecuencia en los pines D5 y D6, perderá las funciones de tiempo (millis (), delay (), pulseIn (), setTimeout () y otras), no funcionarán correctamente . ¡Las bibliotecas Arduino que las usan también dejarán de funcionar!

Si todavía quieres cambiar la frecuencia PWM

Si realmente desea o necesita un PWM overclockeado en el temporizador del sistema (cero) sin perder funciones de tiempo, puede corregirlo de la siguiente manera:

#define micros() (micros() >> CORRECT_CLOCK)
#define millis() (millis() >> CORRECT_CLOCK)
void fixDelay(uint32_t ms) {
  delay(ms << CORRECT_CLOCK);
}

Las definiciones deben colocarse antes de enlazar las bibliotecas para que puedan ingresar al código y reemplazar funciones. Lo único es que no podrá ajustar el retraso dentro de otra biblioteca de esta manera, usted mismo puede usarfixDelay () como está escrito arriba.

Lo más importante – CORRECT_CLOCK. Este es un número entero igual a la relación entre el divisor del temporizador predeterminado y el nuevo conjunto (para overclocking PWM). Por ejemplo, configure el PWM en 8 kHz. De la lista anterior, vemos que el divisor predeterminado es 64, y 7.8 kHz será 8, es decir, 8 veces menos. En CORRECT_CLOCK ponemos el apropiado.

#define CORRECT_CLOCK 8
void fixDelay ( uint32_t ms ) {  
  delay(ms << CORRECT_CLOCK);
}
void setup() {
  pinMode ( 13 , 1 ) ;
  // Pines D5 y D6 - 4 kHz
  TCCR0B = 0b00000010 ; // x8
  TCCR0A = 0b00000001 ; // fase correcta
}
void loop() {
  digitalWrite ( 13 ,! digitalRead ( 13 )) ;
  fixDelay ( 1000 ) ;
}

Bibliotecas para trabajar con PWM.

Además de elegir los registros Arduino manualmente, existen bibliotecas listas para usar que le permiten cambiar la frecuencia PWM de Arduino. Echemos un vistazo a algunas de ellas:

  • Biblioteca de PWM ( GitHub ) – una biblioteca de gran alcance que le permite cambiar la frecuencia PWM de Arduino ATmega48 / 88/ 168 / 328 /640/1280/1281/ 2560 /2561, 328 y en Arduino UNO / nano / Mini, y en 2560 – y Arduino Mega .
    • Le permite configurar cualquier frecuencia PWM, preescaler, TOP.
    • Cuando se trabaja con temporizadores de 8 bits, solo hay un canal disponible (por ejemplo , D3 , D5 , D9 y D10 permanecerán en el ATmega328 )
    • Le permite trabajar con temporizadores de 16 bits a una resolución más alta (16 bits en lugar del estándar de 8)
    • La biblioteca es muy difícil de escribir, no será posible desarmarla pieza por pieza.
    • ¡Vea ejemplos en la carpeta de la biblioteca!
  • La biblioteca GyverPWM ( GitHub ). La biblioteca permite un trabajo muy flexible con PWM en Arduino ATmega328.
    • Le permite configurar cualquier frecuencia PWM en el rango de 250 Hz – 200 kHz.
    • Elección del ancho de bits : 4-8 bits para temporizadores de 8 bits, 4-16 bits para temporizadores de 16 bits (con 4 bits, la frecuencia PWM es 1 MHz 😀).
    • Elección del modo de funcionamiento PWM: PWM rápido o PWM con corrección de fase (especial para motores eléctricos).
    • Genera una onda cuadrada en el pin D9 de 2 Hz a 8 MHz con máxima precisión.
    • Cuando se trabaja con temporizadores de 8 bits, solo hay un canal disponible (por ejemplo , D3 , D5 , D9 y D10 permanecerán en el ATmega328 ).
    • Existen funciones para reconfigurar el PWM estándar, en las que las salidas PWM no se pierden.
    • La biblioteca está escrita de manera muy simple, puede tomar el código en pedazos.
    • ¡Vea ejemplos en la carpeta de la biblioteca!

Deja un comentario