Módulos

Señal de control para motor DC mediante PWM y VHDL

Figura 1: Modulación de ancho de pulso.

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).

Figura 1: Modulación de ancho de pulso.

Figura 1: Modulación de ancho de pulso.

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.

Figura 2: Banco de pruebas del controlador PWM.

Figura 2: Banco de pruebas del controlador PWM.

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.

You Might Also Like

35 Comentarios

  • Responder
    Fermín
    octubre 28, 2012 at 4:58 pm

    Buen aporte!!!

  • Responder
    Brandon
    diciembre 9, 2013 at 11:48 am

    Hola 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

  • Responder
    Brandon
    diciembre 10, 2013 at 12:08 am

    En 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

  • Responder
    Santiago
    diciembre 24, 2013 at 11:49 am

    Amigo 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.

    • Responder
      Carlos Ramos
      diciembre 24, 2013 at 2:37 pm

      Buenas 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 utiliza entrada 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.

  • Responder
    Efrain
    agosto 6, 2014 at 11:29 pm

    Hola, 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.

    • Responder
      Carlos Ramos
      agosto 7, 2014 at 9:32 pm

      Efrain, 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ó con UNSIGNED). Es cuestión de preferencia (al menos para el uso académico que se le da).

      • Responder
        Efrain
        agosto 7, 2014 at 10:11 pm

        OK 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) “

        • Responder
          Carlos Ramos
          agosto 8, 2014 at 7:33 pm

          Efrain, la función rising_edge realiza más comprobaciones que clk'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 que rising_edge solamente se activa cuando la transición es de 0 a 1, mientras que clk'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 usar rising_edge pues es mejor para detectar los flancos de subida que la otra forma. Saludos.

  • Responder
    luis guzman
    noviembre 13, 2014 at 10:26 pm

    disculpa 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.

    • Responder
      Carlos Ramos
      noviembre 17, 2014 at 11:14 pm

      Buenas 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.

  • Responder
    luis guzman
    noviembre 21, 2014 at 9:39 pm

    Lo 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…

  • Responder
    Eduardo Luna
    diciembre 5, 2014 at 8:02 am

    Hola 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

    • Responder
      Carlos Ramos
      diciembre 8, 2014 at 9:34 pm

      Hola, 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.

  • Responder
    Jorge
    noviembre 9, 2015 at 12:31 pm

    Hola 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

    • Responder
      Carlos Ramos
      noviembre 23, 2015 at 10:21 pm

      Jorge, 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.

  • Responder
    Denis
    noviembre 18, 2015 at 5:47 pm

    Hola 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

  • Responder
    jorge
    diciembre 3, 2015 at 1:06 am

    hola 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

  • Responder
    César Bernal
    julio 14, 2016 at 2:06 pm

    Es un buen aporte, implemente el código en un led dual y me funcionó perfectamente.

  • Responder
    Rigoberto
    octubre 12, 2016 at 7:36 am

    Aparte de todo esto
    Cual es la diferencia entre DC signal y pulsacion signal

    • Responder
      Carlos Ramos
      octubre 12, 2016 at 11:57 am

      Ahh… 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?

  • Responder
    SALVADOR
    noviembre 7, 2016 at 7:20 pm

    HOLA 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.

    • Responder
      Carlos Ramos
      noviembre 9, 2016 at 1:39 pm

      Salvador, 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.

  • Responder
    luis albert0
    agosto 18, 2017 at 6:18 pm

    disculpa 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.

    • Responder
      Carlos Ramos
      octubre 16, 2017 at 1:03 am

      Luis, ¿cómo resolviste este problema? ¿qué encoder utilizaste para codificar la información de las vueltas del motor DC?

  • Responder
    jose rivera
    octubre 10, 2017 at 10:54 pm

    Hola 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.

    • Responder
      Carlos Ramos
      octubre 16, 2017 at 1:06 am

      Puedes 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.

  • Responder
    Arcelio
    octubre 3, 2018 at 5:14 am

    hola 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??

    • Responder
      Carlos Ramos
      noviembre 7, 2018 at 9:36 pm

      Arcelio, desconozco la plataforma z7, y no tengo constraints para tal dispositivo. Saludos.

  • Responder
    Gerald Aburto
    julio 27, 2019 at 11:11 pm

    como podriamos hacer para invertir el giro de motor???

  • Responder
    Alejandro Macias
    noviembre 30, 2019 at 9:46 am

    Es 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.

    • Responder
      Alejandro Macias
      noviembre 30, 2019 at 10:03 am

      Es 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.

    Deja tu comentario