Temporizadores AVR-Modo PWM-Parte II

 Serie AVR Este artículo es continuación de la publicación anterior de PWM. Aprenda a programar los temporizadores para que funcionen en modo PWM. ¡Así que empecemos!

Hola amigos! ¡Cuánto tiempo sin verte! 🙂

En mi post anterior, hemos discutido los conceptos básicos de PWM. Resumámoslo primero:

  • PWM significa Modulación de Ancho de pulso.
  • Se puede generar comparando una forma de onda predeterminada con un nivel de voltaje de referencia o haciendo circuitos analógicos simples.
  • El ciclo de trabajo de una forma de onda PWM viene dado por la siguiente relación.
Ciclo de Trabajo
  • Hay tres modos de funcionamiento de PWM: PWM rápido, PWM correcto de fase y PWM correcto de Frecuencia y Fase
  • Cómo elegir el temporizador, el modo de operación y comparar el modo de salida para generar el PWM deseado.
Así que ahora, sin mucha molestia, veamos cómo implementarlo usando los microcontroladores AVR. Antes de continuar, le sugiero que revise mis publicaciones anteriores sobre Temporizadores y PWM.

Tomemos una declaración de problema. Necesitamos generar una señal PWM de 50 Hz con un ciclo de trabajo del 45%.

Análisis

Dado que

Frequency = 50 Hz

En otras palabras, el período de tiempo, T

T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms

También, dado que

Duty Cycle = 45%

Por lo tanto, resolviendo de acuerdo con la ecuación dada anteriormente, obtenemos

T(on) = 9 msT(off) = 11 ms

Ahora, esto puede ser logrado de dos maneras:

  1. Usar Temporizador en Modo CTC
  2. Usar Temporizador en Modo PWM

Metodología-Modo CTC

Está bien, así que no escribiré ningún código aquí (solo el pseudo código). ¡Asumo que después de leer mis publicaciones anteriores, eres lo suficientemente inteligente como para escribir una tú mismo! Discutiremos solo los conceptos.

En primer lugar, elija un temporizador adecuado. Para esta aplicación, podemos elegir cualquiera de los tres temporizadores disponibles en ATMEGA32. Elegir un adecuado prescaler. A continuación, configure el temporizador y proceda como de costumbre. El problema aquí es que necesita actualizar el valor de comparación del registro OCRx cada vez. Una de estas formas se discute en el pseudo código que se da a continuación.

Esto es análogo al intermitente LED tradicional, excepto el hecho de que los tiempos de encendido y apagado son diferentes.

Pseudo Código

#include <avr/io.h>#include <avr/interrupt.h> uint8_t count = 0; // global counter // initialize timer, interrupt and variablevoid timerX_init(){ // set up timerX with suitable prescaler and CTC mode // initialize counter // initialize compare value // enable compare interrupt // enable global interrupts} // process the ISR that is firedISR (TIMERx_COMPA_vect){ // do whatever you want to do here // say, increment the global counter count++; // check for the global counter // if count == odd, delay required = 11 ms // if count == even, delay required = 9 ms // thus, the value of the OCRx should be constantly updated if (count % 2 == 0) OCRx = 9999; // calculate and substitute appropriate value else OCRx = 10999; // calculate and substitute appropriate value} int main(void){ // initialize the output pin, say PC0 DDRC |= (1 << 0); // initialize timerX timerX_init(); // loop forever while(1) { // do nothing }}

Este es un método. Y es muy ineficiente. Puede aumentar su eficiencia escribiendo un mejor código C (en cuanto a sintaxis), sin embargo, el concepto sigue siendo el mismo. Si tiene cualquier otro método / concepto, ¡le invitamos a compartirlo aquí! 🙂

ACTUALIZACIÓN: Uno de los lectores de maxEmbedded, «coolpales» ha escrito este código, y funcionó para él.

¡Tenga en cuenta que este código aún no se ha probado! Por lo tanto, si alguno de ustedes lo está probando, publique sus resultados aquí, ¡me encantaría verlos! 🙂

Metodología – Modo PWM

Está bien, así que ahora vamos a aprender sobre el modo PWM. El modo PWM en AVR está controlado por hardware. Esto significa que todo, con todo quiero decir «todo», lo hace la CPU AVR. Todo lo que necesita hacer es inicializar e iniciar el temporizador, y configurar el ciclo de trabajo. Genial, eh?! ¡Aprendamos cómo!

Aquí, he utilizado Timer0 de ATMEGA32 para la demostración. También puede elegir cualquier otro temporizador o microcontrolador AVR. Ahora echemos un vistazo a los registros.

Registro de control TCCR0 – Temporizador/Contador 0

Hemos encontrado este registro en mi tutorial de Timer0. Aquí, aprenderemos a configurar los bits apropiados para ejecutar el temporizador en modo PWM.

 Registro TCCR0

Registro TCCR0

Discutiremos solo los bits que nos interesan ahora.

  • Bit 6,3-WGM01: 0-Modo de generación de forma de onda – Estos bits se pueden configurar en «00» o «01» dependiendo del tipo de PWM que desee generar. Aquí está la mesa de búsqueda.
     Descripción del Bit del Modo de Generación de Forma de Onda

    Descripción del Bit del Modo de Generación de Forma de Onda

  • Bit 5,4-COM01:0 – Modo de salida de coincidencia de comparación: Estos bits se configuran para controlar el comportamiento del pin de comparación de salida (OC0, pin 4 en ATMEGA32) de acuerdo con los bits WGM01: 0. La siguiente tabla de búsqueda determina las operaciones del pin OC0 para el modo PWM rápido.
     Compare el Modo de salida, el Modo PWM Rápido

    Compare el Modo de salida, el Modo PWM Rápido

    Ahora echemos un vistazo a las formas de onda PWM rápidas. Se puede encontrar una explicación detallada en mi tutorial anterior.

     Fast PWM

    Fast PWM

    Ahora permítanme recordarles que el AVR PWM está totalmente controlado por hardware, lo que significa que incluso la operación de comparación de temporizador la realiza la CPU AVR. Todo lo que necesitamos hacer es decirle a la CPU qué hacer una vez que se produce una coincidencia. Los pines COM01:0 entran en juego aquí. Vemos que al configurarlo en «10 «o» 11″, el pin de salida OC0 se establece o se borra (en otras palabras, determina si el PWM está en modo invertido o en modo no invertido).

    De manera similar para PWM correcto de fase, la tabla de búsqueda y las formas de onda van así.

    Comparar el Modo de Salida, Modo PWM Correcto de Fase

    Comparar el Modo de Salida, Modo PWM Correcto de Fase

    PWM correcto de fase

    PWM correcto de fase

    Incluso aquí, establecer COM01:0 a «10» o «11» determina el comportamiento del pin OC0. Como se muestra en las formas de onda, hay dos instancias: una durante el conteo ascendente y otra durante el conteo descendente. El comportamiento se describe claramente en la tabla de búsqueda.

    Tenga en cuenta que OC0 es un pin de salida. Por lo tanto, los efectos de WGM y COM no entrarán en juego a menos que el registro DDRx esté configurado correctamente. Consulte este tutorial para obtener más información.

  • Bit 2: 0-CS02: 0 – Bits de selección de reloj: Estos bits ya se discuten en el tutorial Timer0.

Registro de comparación de salida OCR0

Hemos encontrado incluso este registro en mi tutorial de Timer0. Usamos este registro para almacenar el valor de comparación. Pero cuando usamos Timer0 en modo PWM, el valor almacenado en él actúa como el ciclo de trabajo (¡obviamente!). En la declaración del problema, dado que el ciclo de trabajo es del 45%, lo que significa

OCR0 = 45% of 255 = 114.75 = 115

¡Y eso es todo! Ahora estamos listos para escribir un código para ella! 🙂

Editar: Nota

El siguiente código explica cómo crear una señal PWM de un ciclo de trabajo deseado. Si desea cambiar su frecuencia, necesita alterar el valor SUPERIOR, lo que se puede hacer utilizando el registro ICRx (que no es compatible con temporizadores de 8 bits). Para el tiempo de 16 bit1, se puede variar usando ICR1A. Discutiré sobre esto pronto cuando discutamos sobre el servocontrol.

Código

Así que aquí va el código. Para obtener más información sobre las operaciones de puertos de E/S en AVR, consulte esto. Para saber sobre manipulaciones de bits, vea esto. Para aprender a usar AVR Studio 5, consulte esto. Para saber cómo está estructurado este código, consulta la publicación de TIMER0 anterior.

#include <avr/io.h>#include <util/delay.h>void pwm_init(){ // initialize TCCR0 as per requirement, say as follows TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t duty; duty = 115; // duty cycle = 45% of 255 = 114.75 = 115 // initialize timer in PWM mode pwm_init(); // run forever while(1) { OCR0 = duty; }}

Declaración de problema

Así que ahora, tomemos otra declaración de problema. ¡Esta va a ser una cosa más práctica a diferencia de la anterior!

Tomemos el intermitente LED tradicional donde necesitamos parpadear un LED a una frecuencia particular. Pero oye, espera, ¿no lo discutimos hace mucho tiempo en este post (desplácese hacia abajo hacia el final)? Hmm, así que vamos a modificarlo para incorporar PWM. A diferencia del intermitente LED tradicional (donde los LED están ENCENDIDOS o APAGADOS), hagamos que brille al máximo brillo, y luego disminuya lentamente su brillo hasta que llegue a cero, y luego aumente de nuevo su brillo lentamente hasta que se convierta en el máximo.

Análisis y código

Entonces, ¿cómo lo hacemos? ¡Sí, lo adivinaste bien! Disminuya el ciclo de trabajo lentamente de 255 a cero, y luego aumente de cero a 255. Dependiendo del ciclo de trabajo, el voltaje aplicado al LED varía y, por lo tanto, el brillo. La siguiente fórmula indica la relación entre el voltaje y el ciclo de trabajo.

V_out ecuación

Así que aquí va el código. No te lo explicaré, puedes decodificarlo tú mismo. Para obtener más información sobre las operaciones de puertos de E/S en AVR, consulte esto. Para saber sobre manipulaciones de bits, vea esto. Para aprender a usar AVR Studio 5, consulte esto. Para saber cómo está estructurado este código, consulta la publicación de TIMER0 anterior.

// program to change brightness of an LED// demonstration of PWM #include <avr/io.h>#include <util/delay.h> // initialize PWMvoid pwm_init(){ // initialize timer0 in PWM mode TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t brightness; // initialize timer0 in PWM mode pwm_init(); // run forever while(1) { // increasing brightness for (brightness = 0; brightness < 255; ++brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // decreasing brightness for (brightness = 255; brightness > 0; --brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // repeat this forever }}

Así que aquí termina mi otro tutorial muy esperado y largo! El siguiente.. Comunicación Serial! ¡Nos vemos!! 🙂

Y sí, si tiene alguna sugerencia, duda, crítica constructiva, etc., ¡le invitamos a escribir una nota a continuación! ¡Suscríbete a mi blog o agarra los canales RSS para mantenerte actualizado!

Write a Comment

Tu dirección de correo electrónico no será publicada.