En este artículo se utiliza VHDL para generar una señal de control para un motor de corriente directa por medio de la modulación de ancho de pulso. Sin embargo, la conexión eléctrica y el circuito de potencia no se discuten.
Ancho de pulso
Para el control de la velocidad de un motor de corriente directa se utiliza la modulación del ancho de pulso (PWM – Pulse Width Modulation) de una señal cuadrada. Con este método de control, el motor gira a una velocidad determinada por el tiempo en alto de la señal (véase la figura 1).
Existen dos conceptos clave para la modulación de la señal: frecuencia y cantidad de estados. La frecuencia puede ser manipulada de manera externa utilizando un divisor de frecuencia. La cantidad de estados hace referencia al número de ciclos de trabajo disponibles. Por ejemplo, un circuito encendido-apagado convencional tiene solamente esos dos estados.
Componente descrito con VHDL
Para el diseño del modulador de ancho de pulsos para motores de corriente continua se plantea un total de 101 estados (un incremento del 1% por estado) con una frecuencia de trabajo determinada de manera externa (es decir, se asume que la señal de reloj para este componente es la correcta para el motor a ser manejado).
---------------------------------------------------------------------------------- -- Compañía: Estado Finito -- Ingeniero: Carlos Ramos -- -- Fecha de creación: 2014/05/03 02:47:32 -- Nombre del módulo: pwm_dc_101 - Behavioral -- Descripción: -- Controlador para motor DC de 101 posiciones. Las posiciones corresponden a un -- porcentaje entre 0 y 100% del ciclo de trabajo, con un incremento del 1% -- entre cada uno de los elementos. -- NOTA: En este módulo no se toma en cuenta la frecuencia de entrada (es decir, -- se asume que la frecuencia de entrada en 'clk' es la correcta para el motor). -- -- Revisión: -- Revisión 0.01 - Archivo creado. ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity pwm_dc_101 is PORT( clk : IN STD_LOGIC; reset : IN STD_LOGIC; entrada: IN STD_LOGIC_VECTOR(6 downto 0); salida : OUT STD_LOGIC ); end pwm_dc_101; architecture Behavioral of pwm_dc_101 is signal cnt : UNSIGNED(6 downto 0); begin contador: process (clk, reset, entrada) begin if reset = '1' then cnt <= (others => '0'); elsif rising_edge(clk) then if cnt = 99 then cnt <= (others => '0'); else cnt <= cnt + 1; end if; end if; end process; -- Asignación de señales -- salida <= '1' when (cnt < UNSIGNED(entrada)) else '0'; end Behavioral;
Las líneas 35 a 45 se encargan de implementar un contador del 0 al 99 (100 estados, 1% por cada uno), mismo que se utiliza para generar la señal con ese porcentaje en alto (línea 47).
Cabe destacar que para este ejemplo se están “desperdiciando” un total de 27 estados (27 = 128) debido a que solo utilizamos 101 de los 128 disponibles. Claro está, la resolución y cantidad de estados depende del diseñador y el código es libre para su modificación y distribución.
Una simulación no hace daño
Un módulo en VHDL no está desarrollado si no incluye su banco de pruebas. Aquí incluyo uno que, en su mayoría, fue creado con el asistente de Xilinx, aunque la parte modificada se encuentra en el listado 2. Para utilizar el banco de pruebas y el módulo en VHDL del controlador, descargar el archivo a continuación:
[wpdm_file id=2]
En el listado 2 se muestra a grandes rasgos la simulación: se prueban los porcentajes bajos de 0% y 1%, algunos valores intermedios como 30% y 80%, y los valores finales de 99% y más allá (ya cualquiera de 100%).
-- Proceso de estímulos. stim_proc: process begin -- Estado de reset. reset <= '1'; wait for 100 ns; reset <= '0'; -- Simulación. entrada <= "0000000"; -- Porcentaje en 0%. wait for clk_period * 200; -- Esperamos dos ciclos completos. entrada <= "0000001"; -- Porcentaje en 1%. wait for clk_period * 200; -- Esperamos dos ciclos completos. entrada <= "0011110"; -- Porcentaje en 30%. wait for clk_period * 200; -- Esperamos dos ciclos completos. entrada <= "1010000"; -- Porcentaje en 80%. wait for clk_period * 200; -- Esperamos dos ciclos completos. entrada <= "1100011"; -- Porcentaje en 99%. wait for clk_period * 200; -- Esperamos dos ciclos completos. entrada <= "1100100"; -- Porcentaje en 100%. wait for clk_period * 200; -- Esperamos dos ciclos completos. entrada <= "1111000"; -- Porcentaje en 120%. wait for clk_period * 200; -- Esperamos dos ciclos completos. wait; end process;
En la figura 2 se muestra el resultado de la simulación, ejecutada durante 35000ns.
Unión con divisor de frecuencia
Para mover la frecuencia de la señal modulada se utiliza un divisor de frecuencia como entrada del componente de PWM mediante el uso de un módulo principal y la instrucción PORT MAP
.
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity pwm_dc_101_clk200Hz is PORT( clk : IN STD_LOGIC; reset : IN STD_LOGIC; entrada: IN STD_LOGIC_VECTOR(6 downto 0); salida : OUT STD_LOGIC ); end pwm_dc_101_clk200Hz; architecture Behavioral of pwm_dc_101_clk200Hz is COMPONENT clk200Hz IS PORT ( entrada: IN STD_LOGIC; reset : IN STD_LOGIC; salida : OUT STD_LOGIC ); END COMPONENT; COMPONENT pwm_dc_101 IS PORT( clk : IN STD_LOGIC; reset : IN STD_LOGIC; entrada: IN STD_LOGIC_VECTOR(6 downto 0); salida : OUT STD_LOGIC ); END COMPONENT; signal clk_out : STD_LOGIC := '0'; begin clk200Hz_i: clk200Hz PORT MAP(clk, reset, clk_out); pwm_dc_101_i: pwm_dc_101 PORT MAP(clk_out, reset, entrada, salida); end Behavioral;
La señal clk_out
(línea 31) se utiliza para almacenar la salida del divisor de frecuencia y utilizarla como entrada para el modulador.
El código para el PWM para DC unido con el divisor de frecuencia, con su respectivo banco de pruebas, puede ser descargado aquí:
[wpdm_file id=3]
Conclusión
En este artículo se desarrollo un modulador con 101 estados que determinan el porcentaje en alto. Sin embargo, se puede cambiar la cantidad de estados y la resolución (cantidad de bits) que utiliza para generar la señal. Además, el listado 3 demuestra un método efectivo para modificar la frecuencia de operación mediante el uso componentes externos al modulador, en este caso un divisor de frecuencia.
35 Comentarios
Fermín
octubre 28, 2012 at 4:58 pmBuen aporte!!!
Carlos Ramos
diciembre 9, 2013 at 2:06 pmGracias, Fermín :).
Brandon
diciembre 9, 2013 at 11:48 amHola que tal soy nuevo en VHDL, quiero hacer una comunicacion serial en este lenguaje para una Nexys3 pero no se como, tendras algun programa que me pases para ver su estructura.
Mi plan es conectar serialmente arduino y la nexys. En la nexys lo que quiero hacer es solo recibir algunn dato enviado por arduino, digamos que yo de arduino envio el numero 2 y que la nexys al recibir este dato que encienda algun led
Carlos Ramos
diciembre 9, 2013 at 2:03 pmBuenas tardes, Brandon. ¿Has probado los componentes que provee Digilent? Los puedes encontrar en la página del PmodRS232, tanto el componente de referencia como un ejemplo de su uso. Por favor, comunícame si dichos componentes resuelven tu problema.
Brandon
diciembre 10, 2013 at 12:08 amEn el ejemplo del listado 1 las entradas “reset” y “entrada” no se les asocia ningun elemento fisico que determine su estado 0 o 1, digamos un switch o push button ?
El unico puerto que sera asociado para la salida sera “salida” ?
No se si me de a entender, digamos que yo tengo A y B como entradas y LED como salida, en el programa quedaria
LED <= A and B, si esto lo implemento en la misma tarjeta de desarrollo fpga las entradas las asociaria a dos botones y dependiendo de sus estado encendere el led
Santiago
diciembre 24, 2013 at 11:49 amAmigo no entiendo el uso de la variable entrada en el listado 1, también las lineas 33 y 34 del listado 2.
si me pudieras dar una breve explicación sobre esto.
Gracias.
Carlos Ramos
diciembre 24, 2013 at 2:37 pmBuenas tardes, Santiago. El control PWM se basa en una onda cuadrada que presenta variaciones del tiempo en alto (como se muestra en la figura 1). Siendo un amante del sistema decimal, decidí crear una modulación de ancho de pulso con cien estados distintos (razón por la cual
cnt
va de 0 a 99). Pero se necesita una forma para saber qué tanto de esos cien estados va en alto, es para esa tarea que se utilizaentrada
como un número que indica qué porcentaje de esos cien estados estará la señal en alto.Respecto a tu segunda pregunta, la instrucción
PORT MAP
sirve para unir diferentes componentes previamente hechos. Puedes encontrar una explicación un tanto más amplia en Un corto cuento de hadas sobre PORT MAP. Espero haber respondido tus preguntas de una manera adecuada, Santiago. Saludos y gracias por el comentario :D.Efrain
agosto 6, 2014 at 11:29 pmHola, buen aporte.
Una pregunta el cnt en lugar de ser UNSIGNED se puede declarar INTEGER 0 to 99 y compararlo digamos con otra variable tipo INTEGER de la misma longitud pero que esta varie dependiendo de el ciclo de trabajo seleccionando.
Carlos Ramos
agosto 7, 2014 at 9:32 pmEfrain, claro, se pueden hacer hacer por medio de
INTEGER
, aunque será necesario una conversión de tipos en caso de comparación entre vectores de bits y enteros (semejante a la que se realizó conUNSIGNED
). Es cuestión de preferencia (al menos para el uso académico que se le da).Efrain
agosto 7, 2014 at 10:11 pmOK muchas gracias. Otra cosa bueno si no es mucha molestia, pero podrías explicarme cual es la diferencia entre usar “clk’ event and clk = ‘1’ ” o usar ” rising_edge(clk) “
Carlos Ramos
agosto 8, 2014 at 7:33 pmEfrain, la función
rising_edge
realiza más comprobaciones queclk'event and clk = '1'
, por lo cual es preferible que se utilice en los diseños. En este blog no se ha visto una diferencia entre ambas formas, pues la diferencia está en querising_edge
solamente se activa cuando la transición es de 0 a 1, mientras queclk'event and clk = '1'
se activa cuando la señal sea 1, independiente del estado anterior. Aquí no se han utilizado los otros estados (indefinido, no importa, alta impedancia, débil, fuerte), motivo por el cual se podría decir que son equivalentes (de nuevo, en e lalcance de este blog). Empero, es preferible mantener la costumbre de usarrising_edge
pues es mejor para detectar los flancos de subida que la otra forma. Saludos.luis guzman
noviembre 13, 2014 at 10:26 pmdisculpa igual soy nuevo en esto de vhdl, para realizar una practica donde pueda controlar 3 motores con un pld seria con un programa parecido a este, necesito orientacion. Espero leas mi mensaje muchas gracias por tu atencion.
Carlos Ramos
noviembre 17, 2014 at 11:14 pmBuenas noches, Luis. Para controlar tres motores, ¿necesitas que las tres señales sean independientes? ¿o una señal controlará los tres motores (quizá con modificaciones menores en base a una única entrada)? Lo más fácil quizá sería instanciar tres componentes de motor mediante
PORT MAP
, asignando posteriormente los pines de entrada y salida en el componente principal. Saludos.luis guzman
noviembre 21, 2014 at 9:39 pmLo que el profe nos pide es que en físico podamos controlar cada motor con dos botones (push boton) que con un boton el boton gire hacia la izquierda y con otro boton gire a la derecha, ya sea un motor de CD, CA, motor a paso, etc. Creo que me podria servir el programa que tiene aqui en tu foro el que dice: 2.Control de Servomotores mediante VHDL y Dos Botones. Si se podría usar, aunque no se que tendría que modificar para poder controlar los 3 motores…
Eduardo Luna
diciembre 5, 2014 at 8:02 amHola sabes tengo un proyecto final, nos solicitan controlar la posición especifica de 2 servos
debe incluir estado presente,actual,futuro, y cada vez que el se mueva el sensor saber donde se encuentra con un código binario que después decoficaremos en un display de 7 segmentos.
necesito su ayuda para controlar la posición de los servos.
en espera de comentarios
saludos
Carlos Ramos
diciembre 8, 2014 at 9:34 pmHola, Eduardo. ¿Ya revisaste la entrada correspondiente al control de servomotores? Mejor aún, ¿ya sabes la frecuencia de operación, cantidad de posiciones, y ciclo de trabajo para tu servo en particular? Todo se reduce a conocer esos datos, y unos pocos cálculos. Una duda, ¿con qué entrada moverás los servos (e.g. botones, ratón, teclado)? Saludos.
Jorge
noviembre 9, 2015 at 12:31 pmHola buen aporte soy nuevo en vhdl me preguntaba si este código seria útil para impementqr él control de un motor de altas revoluciones como es él de los cuadropteros o drones mediante él giroscopio de la tarjeta nano 0 de altera gracias..buen dia
Carlos Ramos
noviembre 23, 2015 at 10:21 pmJorge, no tengo respuesta a esa pregunta. No sé qué tipo de control necesites, pero asumiré que si es de alta velocidad, y para los drones, necesitas un sistema de control que se actualice cada cierta frecuencia. Tendrás unas cuantas ecuaciones que resolver para el control.
Como dije, desconozco el tema, aunque si tuviera que elegir una respuesta, sería “lo dudo”.
Busca un controlador más sofisticado, en sitios como OpenCores.
Denis
noviembre 18, 2015 at 5:47 pmHola carlos, he probado este proyecto, pero cuando lo simulo, no me genera la señal pwm, pasado unos ns la salida se pone a 1, y asi se mantiene. Que puedo hacer al respecto. SALUDOS
jorge
diciembre 3, 2015 at 1:06 amhola carlos nuevamente por aqui tenia una duda respecto a entrada: IN STD_LOGIC_VECTOR(6 downto 0); esta que funcion me desempeña y como la puedo declarar en pin planer
entiendo que clock es el reloj interno reset un boton salida un pin para pwm y ahi mi duda como colocar entrada: IN STD_LOGIC_VECTOR(6 downto 0); gracias antemano
César Bernal
julio 14, 2016 at 2:06 pmEs un buen aporte, implemente el código en un led dual y me funcionó perfectamente.
Carlos Ramos
julio 15, 2016 at 7:35 amCésar, ¡un gusto saber que te fue de utilidad!
Rigoberto
octubre 12, 2016 at 7:36 amAparte de todo esto
Cual es la diferencia entre DC signal y pulsacion signal
Carlos Ramos
octubre 12, 2016 at 11:57 amAhh… Primero, que nada, la “señal DC” no existe. ¿Te refieres a la corriente directa en sí o a la señal de modulación por ancho de pulsos?
Sobre la “señal de pulsación”… supongo que es lo mismo. Al menos, si lo buscas en Google, te manda a la definición de PWM.
La verdad, no estoy seguro de a qué te refieres con tu pregunta. Tanto como a la primera señal como a la segunda, ¿de dónde sacaste esos nombres?
SALVADOR
noviembre 7, 2016 at 7:20 pmHOLA QUE TAL.
NECESITO AYUDA PARA UN PROYECTO QUE ME PIDIERON EN LA ESC. Y NO TENGO IDEA DE COMO LLEGAR A ESTO. O NECESITO TU AYUDA. OJALA Y ME PUEDAS AYUDAR. ESTOS SON LOS REQUISITOS QUE ME PIDIERON Y LO TENGO QUE HACER A 50 HZ.
Será manipulado mediante dos botones, uno para incrementar y el otro para decrementar el ciclo de
trabajo
del PWM
.Cuando se pulsen los botones el ciclo de trabajo aumentará o d
isminuirá en saltos de 5%.
El límite inferior será 5% y el superior 95%, los cuales no se deberán sobrepasar.
En el display deberá mostrarse el porcentaje del ciclo del trabajo.
La frecuencia de operación del PWM será fijada por el alumno previamente,
En el reset el ciclo de trabajo debe ser de 50% (al inicio o cuando se presione el botón Reset).
Habilitar un pin de uso general para dar salida a la salida de PWM, la cual debe observarse mediante
osci
loscopio
UN SALUDO Y OJALA Y ME PUEDAS AYUDAR.
Carlos Ramos
noviembre 9, 2016 at 1:39 pmSalvador, aprecio tu comentario.
No obstante, asumo que no te diste el tiempo de pasar por la página de contacto, donde establezco algunos lineamientos para hacer esta clase de preguntas.
Una vez hayas trabajado en tu problema, y tengas evidencia de ello, proseguimos.
Saludos.
luis albert0
agosto 18, 2017 at 6:18 pmdisculpa igual soy nuevo en esto de vhdl, para realizar una practica donde nos piden que mostremos los revoluciones por min de un motor de cd y que este se visualice en el display de 7segmentos, necesito orientacion. Espero leas mi mensaje muchas gracias por tu atencion.
Carlos Ramos
octubre 16, 2017 at 1:03 amLuis, ¿cómo resolviste este problema? ¿qué encoder utilizaste para codificar la información de las vueltas del motor DC?
jose rivera
octubre 10, 2017 at 10:54 pmHola buenas noches, comenzando por el mundo de VHDL, pero necesito hacer un programa que varie en 3 segundos la intensidad de un led, externo de la tablilla CoolrunnerII siendo en este que de 0 a 1.5 seg, vaya aumentando hasta encender el led, y de 1.5 seg disminuya la intensidad hasta apargar el led. si me orientaras te lo agradecería.
Carlos Ramos
octubre 16, 2017 at 1:06 amPuedes ir apagando el LED controlando el tiempo que está en alto, y controlar el tiempo que dura apagándose con un divisor de frecuencia diferente cada vez, o con un contador que incrementa o disminuye su límite en base al tiempo requerido.
Así pues, serían dos cosas: 1) generar la señal de PWM para ir apagando el LED, y 2) una forma de manipular un contador para variar el límite de conteo según el tiempo que deba durar apagando o prendiendo.
Arcelio
octubre 3, 2018 at 5:14 amhola buenos días, estoy realizando un proyecto para el control de un pulso PWM en su periodo, pero mi pregunta es lo puedo implementar en una FPGA z7 y los contraint los tienes definidos??
Carlos Ramos
noviembre 7, 2018 at 9:36 pmArcelio, desconozco la plataforma z7, y no tengo constraints para tal dispositivo. Saludos.
Gerald Aburto
julio 27, 2019 at 11:11 pmcomo podriamos hacer para invertir el giro de motor???
Alejandro Macias
noviembre 30, 2019 at 9:46 amEs posible asignar las entradas “clk”, “Entrada” y “Reset” a las terminales de un encoger rotatorio para que este realice el respectivo control o es necesario modificar el codigo?. saludos.
Alejandro Macias
noviembre 30, 2019 at 10:03 amEs posible asignar las entradas «clk», «Entrada» y «Reset» a las terminales de un encoder rotatorio para que este realice el respectivo control, en caso de ser posible “Entrada” a que terminar del encoder se conectaria. saludos.