- ¿Qué es una señal PWM?
- Programación de PIC para generar PWM en pines GPIO
- Diagrama de circuito
- Simulación
- Configuración de hardware para controlar el servomotor mediante el microcontrolador PIC
La generación de señales PWM es una herramienta vital en todo arsenal de ingenieros integrados, son muy útiles para muchas aplicaciones como controlar la posición del servomotor, cambiar algunos circuitos integrados electrónicos de potencia en convertidores / inversores e incluso para un simple control de brillo de LED. En los microcontroladores PIC, las señales PWM se pueden generar utilizando los módulos de comparación, captura y PWM (CCP) configurando los registros requeridos, ya hemos aprendido cómo hacerlo en el tutorial PIC PWM. Pero hay un inconveniente considerable con ese método.
El PIC16F877A puede generar señales PWM solo en los pines RC1 y RC2, si usamos los módulos CCP. Pero podemos encontrar situaciones en las que necesitemos más pines para tener la funcionalidad PWM. Por ejemplo, en mi caso, quiero controlar 6 servomotores RC para mi proyecto de brazo robótico para el cual el módulo CCP es inútil. En estos escenarios, podemos programar los pines GPIO para producir señales PWM usando módulos de temporizador. De esta manera podemos generar tantas señales PWM con cualquier pin requerido. También hay otros trucos de hardware como el uso de un IC multiplexor, pero ¿por qué invertir en hardware cuando se puede lograr lo mismo mediante la programación? Entonces en este tutorial aprenderemos cómo convertir un pin PIC GPIO en un pin PWM y para probarlo lo simularemos en proteus con osciloscopio digital y tambiéncontrole la posición del servomotor usando la señal PWM y varíe su ciclo de trabajo variando un potenciómetro.
¿Qué es una señal PWM?
Antes de entrar en detalles, repasemos un poco qué son las señales PWM. La modulación de ancho de pulso (PWM) es una señal digital que se usa con mayor frecuencia en los circuitos de control. Esta señal se establece en alto (5v) y bajo (0v) en un tiempo y velocidad predefinidos. El tiempo durante el cual la señal permanece alta se denomina "tiempo de activación " y el tiempo durante el cual la señal permanece baja se denomina "tiempo de inactividad". Hay dos parámetros importantes para un PWM como se describe a continuación:
Ciclo de trabajo del PWM
El porcentaje de tiempo en el que la señal PWM permanece ALTA (a tiempo) se denomina ciclo de trabajo. Si la señal está siempre encendida, está en un ciclo de trabajo del 100% y si siempre está apagada, es un ciclo de trabajo del 0%.
Ciclo de trabajo = tiempo de encendido / (tiempo de encendido + tiempo de apagado)
Nombre de la variable |
Se refiere a |
PWM_Frequency |
Frecuencia de la señal PWM |
T_TOTAL |
Tiempo total necesario para un ciclo completo de PWM |
TONELADA |
A tiempo de la señal PWM |
PETIMETRE |
Tiempo de apagado de la señal PWM |
Ciclo de trabajo |
Ciclo de trabajo de la señal PWM |
Así que ahora, hagamos los cálculos.
Estas son las fórmulas estándar donde la frecuencia es simplemente el recíproco del tiempo. El valor de la frecuencia debe ser decidido y establecido por el usuario en función de los requisitos de su aplicación.
T_TOTAL = (1 / PWM_Frequency)
Cuando el usuario cambia el valor del ciclo de trabajo, nuestro programa debe ajustar automáticamente el tiempo T_ON y el tiempo T_OFF de acuerdo con eso. Por lo tanto, las fórmulas anteriores se pueden usar para calcular T_ON según el valor de Duty_Cycle y T_TOTAL.
T_ON = (Duty_Cycle * T_TOTAL) / 100
Dado que el tiempo total de la señal PWM para un ciclo completo será la suma del tiempo de encendido y apagado. Podemos calcular el tiempo de inactividad T_OFF como se muestra arriba.
T_OFF = T_TOTAL - T_ON
Con estas fórmulas en mente, podemos comenzar a programar el microcontrolador PIC. El programa involucra el módulo de temporizador PIC y el módulo PIC ADC para crear una señal PWM basada con un ciclo de trabajo variable de acuerdo con el valor ADC del POT. Si es nuevo en el uso de estos módulos, se recomienda encarecidamente leer el tutorial correspondiente haciendo clic en los hipervínculos.
Programación de PIC para generar PWM en pines GPIO
El programa completo de este tutorial se puede encontrar en la parte inferior del sitio web como siempre. En esta sección, entendamos cómo está escrito realmente el programa. Como todos los programas, comenzamos por establecer los bits de configuración. He utilizado la opción de vistas de memoria para configurarla.
// CONFIG #pragma config FOSC = HS // Bits de selección del oscilador (oscilador HS) #pragma config WDTE = OFF // Bit de habilitación del temporizador de vigilancia (WDT deshabilitado) #pragma config PWRTE = OFF // Bit de habilitación del temporizador de encendido (PWRT disabled) #pragma config BOREN = ON // Bit de habilitación de reinicio de bajada (BOR habilitado) #pragma config LVP = OFF // Bit de habilitación de programación en serie en circuito de bajo voltaje (suministro único) (RB3 es E / S digital, HV en MCLR debe usarse para la programación) #pragma config CPD = OFF // Bit de protección de código de memoria EEPROM de datos (protección de código EEPROM de datos desactivada) #pragma config WRT = OFF // Bits de habilitación de escritura de memoria de programa flash (protección de escritura desactivada; toda la memoria del programa puede ser escrita por el control EECON) #pragma config CP = OFF // Bit de protección de código de memoria de programa flash (protección de código desactivada) // # Las declaraciones de configuración de pragma deben preceder al archivo de proyecto incluido. // Usa enumeraciones del proyecto en lugar de #define para ON y OFF. #incluir
Luego mencionamos la frecuencia de reloj utilizada en el hardware, aquí mi hardware usa cristal de 20MHz, puede ingresar el valor basado en su hardware. Seguido de eso está el valor de frecuencia de la señal PWM. Dado que mi objetivo aquí es controlar un servomotor RC de hobby que requiere una frecuencia PWM de 50Hz, he establecido 0.05KHz como valor de frecuencia, también puede cambiar esto según los requisitos de su aplicación.
#define _XTAL_FREQ 20000000 #define PWM_Frequency 0.05 // en KHz (50Hz)
Ahora que tenemos el valor de Frecuencia, podemos calcular el T_TOTAL usando las fórmulas discutidas anteriormente. El resultado se sumerge en 10 para obtener el valor del tiempo en milisegundos. En mi caso, el valor de T_TOTAL será de 2 milisegundos.
int T_TOTAL = (1 / PWM_Frequency) / 10; // calcular el tiempo total a partir de la frecuencia (en milisegundos)) // 2 ms
Seguido de eso, inicializamos los módulos ADC para leer la posición del potenciómetro como se explica en nuestro tutorial ADC PIC. A continuación tenemos la rutina de servicio de interrupción que se llamará cada vez, el temporizador se desborda, volveremos a esto más adelante, por ahora, verifiquemos la función principal.
Dentro de la función principal configuramos el módulo temporizador. Aquí he configurado el módulo del temporizador para que se desborde cada 0,1 ms. El valor del tiempo se puede calcular usando las fórmulas siguientes
RegValue = 256 - ((Delay * Fosc) / (Prescalar * 4)) retraso en seg y Fosc en hz
En mi caso para un retardo de 0.0001 segundos (0.1ms) con prescalar de 64 y Fosc de 20MHz el valor de mi registro (TMR0) debería ser 248. Entonces la configuración se ve así
/ ***** Configuración de puerto para temporizador ****** / OPTION_REG = 0b00000101; // Timer0 con frecuencia externa y 64 como prescalar // También habilita PULL UPs TMR0 = 248; // Cargue el valor de tiempo para 0.0001s; delayValue puede estar entre 0-256 solo TMR0IE = 1; // Habilita el bit de interrupción del temporizador en el registro PIE1 GIE = 1; // Habilitar la interrupción global PEIE = 1; // Habilita la interrupción de periféricos / *********** ______ *********** /
Luego tenemos que establecer la configuración de Entrada y Salida. Aquí estamos usando el pin AN0 para leer el valor ADC y los pines PORTD para emitir las señales PWM. Así que inícialos como pines de salida y hazlos bajos usando las siguientes líneas de código.
/ ***** Configuración de puerto para E / S ****** / TRISD = 0x00; // Indique a la MCU que todos los pines del PUERTO D tienen salida PORTD = 0x00; // Inicializar todos los pines a 0 / *********** ______ *********** /
En el interior del infinito , mientras que bucle, tenemos que calcular el valor de la hora (T_ON) del ciclo de trabajo. El tiempo y deber ciclo varía en función de la posición de la olla para lo hacemos repetidamente dentro del tiempo de bucle como se muestra a continuación. 0.0976 es el valor que hay que multiplicar por 1024 para obtener 100 y para calcular T_ON lo hemos multiplicado por 10 para obtener el valor en milisegundos.
while (1) { POT_val = (ADC_Read (0)); // Leer el valor de POT usando ADC Duty_cycle = (POT_val * 0.0976); // Asignar 0 a 1024 a 0 a 100 T_ON = ((Duty_cycle * T_TOTAL) * 10/100); // Calcula el tiempo de espera usando la unidad de fórmulas en milisegundos __delay_ms (100); }
Dado que el temporizador está configurado para desbordar cada 0,1 ms, se llamará a la rutina de servicio de interrupción del temporizador ISR cada 0,1 ms. Dentro de la rutina de servicio usamos una variable llamada count y la incrementamos por cada 0.1ms. De esta manera podemos realizar un seguimiento del tiempo. Para obtener más información sobre las interrupciones en el microcontrolador PIC, siga los enlaces
if (TMR0IF == 1) // El indicador del temporizador se ha activado debido a un desbordamiento del temporizador -> configurado en desbordamiento por cada 0,1 ms { TMR0 = 248; // Carga el temporizador Valor TMR0IF = 0; // Borrar el conteo de banderas de interrupción del temporizador ++; // Contar incrementos por cada 0.1ms -> count / 10 dará el valor del conteo en ms }
Finalmente, es hora de alternar el pin GPIO en función del valor de T_ON y T_OFF. Tenemos la variable de conteo que realiza un seguimiento del tiempo en milisegundos. Entonces usamos esa variable para verificar si el tiempo es menor que el tiempo , si es así, mantenemos el pin GPIO encendido; de lo contrario, lo apagamos y lo mantenemos apagado hasta que comience el nuevo ciclo. Esto se puede hacer comparándolo con el tiempo total de un ciclo PWM. El código para hacer lo mismo se muestra a continuación.
if (count <= (T_ON)) // Si el tiempo es menor que el tiempo RD1 = 1; // Enciende GPIO else RD1 = 0; // De lo contrario, apague GPIO if (count> = (T_TOTAL * 10)) // Manténgalo apagado hasta que comience un nuevo ciclo count = 0;
Diagrama de circuito
El diagrama de circuito para generar PWM con el pin GPIO del microcontrolador PIC es realmente simple, solo encienda el PIC con el oscilador y conecte el potenciómetro al pin AN0 y el Servo Motor al pin RD1, podemos usar el pin GPIO para obtener la señal PWM, he seleccionado RD1 simplemente al azar. Tanto el potenciómetro como el servomotor funcionan con 5 V que se regulan desde el 7805 como se muestra a continuación en el diagrama del circuito.
Simulación
Para simular el proyecto utilicé mi software proteus. Construya el circuito que se muestra a continuación, vincule el código a su simulación y ejecútelo. Debe obtener una señal PWM en el pin RD1 GPIO según nuestro programa y el ciclo de trabajo del PWM debe controlarse en función de la posición del potenciómetro. El siguiente GIF muestra cómo responden la señal PWM y el servomotor cuando el valor de ADC se cambia a través del potenciómetro.
Configuración de hardware para controlar el servomotor mediante el microcontrolador PIC
Mi configuración de hardware completa se muestra a continuación, para las personas que siguen mis tutoriales, esta placa debería resultar familiar, es la misma placa que he usado en todos mis tutoriales hasta ahora. Puede consultar el tutorial de LED parpadeante si está interesado en saber cómo lo construyo. De lo contrario, siga el diagrama de circuito anterior y todo debería funcionar bien.
Cargue el programa y varíe el potenciómetro y debería ver que el servo cambia la posición según la posición del potenciómetro. El funcionamiento completo del proyecto se muestra en el video que se encuentra al final de esta página. Espero que haya entendido el proyecto y haya disfrutado de la construcción, si tiene preguntas, no dude en publicarlas en el foro y haré todo lo posible para responder.
Estoy planeando llevar adelante este proyecto agregando opciones para controlar múltiples servomotores y así construir un brazo robótico con él, similar al Arduino Robotic Arm que ya construimos. ¡¡Hasta entonces nos vemos !!