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