Estrella de Navidad con CPLD 
El proyecto navideño de este año es una sencilla estrella de navidad que puede colocarse tanto en el árbol como en el belén y que requiere de muy poca circuitería.

Idea

El objetivo era no recurrir a la típica luz parpadeante sino darle un efecto de movimiento, que parezca que la estrella se mueva por el firmamento. Para simular este efecto lo más sencillo es alinear varias luces y hacer que la luz se mueva rápidamente, con un brillo creciente y en una dirección concreta, lo que da el efecto de que la luz un efecto meteorito.

Diseño eléctrico

A nivel electrónico el concepto es muy sencillo: 8 leds de alta luminosidad protegidos con resistencias y conectados a 8 salidas de un CPLD.

Uno de los leds hace de estrella principal mientras que los 7 leds restantes servirán para hacer el efecto de la estela de la estrella principal. La secuencia de iluminación será la siguiente:

- E0 iluminado al 5%, resto apagado

- E1 iluminado al 10%, resto apagado

- E2 iluminado al 15%, resto apagado

- E3 iluminado al 20%, resto apagado

- E4 iluminado al 30%, resto apagado

- E5 iluminado al 40%, resto apagado

- E6 iluminado al 50%, resto apagado

- EP iluminado al 100% durante varias unidades de tiempo más, resto apagado

- Todo apagado durante varias unidades de tiempo

Diseño lógico y funcionamiento

A continuación una propuesta de diagrama de bloques sencillo:

Al circuito combinacional A tiene como entradas el valor del registro contador de 22 bits y el valor del registro de desplazamiento de 20 bits y como salida la entrada de selección del multiplexor del registro de desplazamiento de 20 bits:

registro contadorreg. desplaz.mux
x0valor 1
0xsalida desplazador izquierda
≠0≠0reg. desplaz. (mantener)


El registro contador se utiliza con dos propósitos:

- Como medida de unidad de tiempo: Cada vez que se desborda, se desplaza el registro de desplazamiento. A 50 MHz de frecuencia de reloj, tenemos una frecuencia de desplazamiento de ${50000000 \over {2^{22}}} = 11.92093 \: Hz$, es decir ${1 \over 11.92093} = 0.08389 \: seg$, aproximadamente una décima de segundo como unidad de tiempo.

- Como registro contador para el PWM de los leds de la estela: Como es un contador estándar de desbordamiento, se pueden usar los 10 bits menos significativos para generar una señal PWM, esto nos da una frecuencia de señal PWM de ${50000000 \over {2^{10}}} \approx 49 \: KHz$ que es una buena frecuencia para un led.

Al iniciarse el CPLD todos los bits del registro de desplazamiento estarán a 0, lo que provocará que el circuito combinacional A emita un 1 para que, en el primer ciclo de reloj, se cargue un 1 en el registro de desplazamiento. A partir de aquí el circuito combinacional A mantendrá el multiplexor en modo "copia" (manteniendo el valor del registro de desplazamiento) y sólo mandará a desplazar cuando el registro contador se desborde. El registro de desplazamiento tendrá un bit 1 moviéndose de izquierda a derecha a razón de un salto cada décima de segundo, cuando el bit llega al extremo izquierdo aparece de nuevo en el extremo derecho del registro (formalmente deberíamos llamar al registro de desplazamiento, registro de "rotación").

Los 5 bits menos significativos del registro de desplazamiento no se conectan a nada, lo que significa que durante unas 5 décimas de segundo (medio segundo aproximadamente) ninguna de las luces se enciende, cuando el 1 pasa al bit 5 del registro de desplazamiento, se pone a 1 la entrada inferior de la puerta AND que gobierna el led E0, que hace las veces de enable para la salida PWM con menor ciclo de trabajo (menor luminosidad). Cuando el 1 pasa al bit 6 del registro de desplazamiento, se pone a 1 la entrada inferior de la puerta AND que gobierna el led E1, que hace de enable para la salida PWM con ciclo de trabajo ligeramente superior (un poco más de limunosidad que el anterior) y así sucesivamente. A medida que el 1 va desplazándose a la izquierda (un salto por cada décima de segundo aproximadamente) se van iluminando los leds E0 a E6 de forma consecutiva y con ciclos de trabajo PWM crecientes (es decir, cantidad de luz creciente). Los últimos 8 bits del registro de desplazamiento (bits 19 al 12) están conectados a una puerta OR que gobierna la luz EP (estrella principal), esto hace que la estrella principal esté encendida unas 8 décimas de segundo, y luego vuelta a empezar.

Implementación

A continuación el código VHDL:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity MaxIIBethlehemStar is
    port (
        ClkIn       : in std_logic;
        BoardLedOut : out std_logic;
        StarOut     : out std_logic;
        Wake1Out    : out std_logic;
        Wake2Out    : out std_logic;
        Wake3Out    : out std_logic;
        Wake4Out    : out std_logic;
        Wake5Out    : out std_logic;
        Wake6Out    : out std_logic;
        Wake7Out    : out std_logic
    );
end entity;

architecture A of MaxIIBethlehemStar is
    constant Intensity1PWM : integer := 100;   -- over 1024
    constant Intensity2PWM : integer := 83;
    constant Intensity3PWM : integer := 66;
    constant Intensity4PWM : integer := 50;
    constant Intensity5PWM : integer := 35;
    constant Intensity6PWM : integer := 20;
    constant Intensity7PWM : integer := 10;
    signal TimerDBus : std_logic_vector(21 downto 0);
    signal TimerQBus : std_logic_vector(21 downto 0);
    signal ShiftDBus : std_logic_vector(19 downto 0);
    signal ShiftQBus : std_logic_vector(19 downto 0);
    signal Intensity1 : std_logic;
    signal Intensity2 : std_logic;
    signal Intensity3 : std_logic;
    signal Intensity4 : std_logic;
    signal Intensity5 : std_logic;
    signal Intensity6 : std_logic;
    signal Intensity7 : std_logic;
begin
    -- intensity signals (using timer lower 10 bits as PWM counter)
    Intensity1 <= '0' when (unsigned(TimerQBus(9 downto 0)) > to_unsigned(Intensity1PWM, 10)) else
                  '1';
    Intensity2 <= '0' when (unsigned(TimerQBus(9 downto 0)) > to_unsigned(Intensity2PWM, 10)) else
                  '1';
    Intensity3 <= '0' when (unsigned(TimerQBus(9 downto 0)) > to_unsigned(Intensity3PWM, 10)) else
                  '1';
    Intensity4 <= '0' when (unsigned(TimerQBus(9 downto 0)) > to_unsigned(Intensity4PWM, 10)) else
                  '1';
    Intensity5 <= '0' when (unsigned(TimerQBus(9 downto 0)) > to_unsigned(Intensity5PWM, 10)) else
                  '1';
    Intensity6 <= '0' when (unsigned(TimerQBus(9 downto 0)) > to_unsigned(Intensity6PWM, 10)) else
                  '1';
    Intensity7 <= '0' when (unsigned(TimerQBus(9 downto 0)) > to_unsigned(Intensity7PWM, 10)) else
                  '1';

    -- timer counter
    process (ClkIn)
    begin
        if (ClkIn'event and (ClkIn = '1')) then
            TimerQBus <= TimerDBus;
        end if;
    end process;

    TimerDBus <= std_logic_vector(unsigned(TimerQBus) + to_unsigned(1, 22));

    -- shift register
    process (ClkIn)
    begin
        if (ClkIn'event and (ClkIn = '1')) then
            ShiftQBus <= ShiftDBus;
        end if;
    end process;

    ShiftDBus <= std_logic_vector(to_unsigned(1, 20)) when (unsigned(ShiftQBus) = 0) else
                 ShiftQBus(18 downto 0) & ShiftQBus(19) when (unsigned(TimerQBus) = 0) else
                     ShiftQBus;

    -- outputs
    StarOut <= ShiftQBus(19) or ShiftQBus(18) or ShiftQBus(17) or ShiftQBus(16) or ShiftQBus(15) or ShiftQBus(14) or ShiftQBus(13) or ShiftQBus(12);
    Wake1Out <= Intensity1 and ShiftQBus(11);
    Wake2Out <= Intensity2 and ShiftQBus(10);
    Wake3Out <= Intensity3 and ShiftQBus(9);
    Wake4Out <= Intensity4 and ShiftQBus(8);
    Wake5Out <= Intensity5 and ShiftQBus(7);
    Wake6Out <= Intensity6 and ShiftQBus(6);
    Wake7Out <= Intensity7 and ShiftQBus(5);

    -- debug
    BoardLedOut <= (ShiftQBus(19) or ShiftQBus(18) or ShiftQBus(17) or ShiftQBus(16) or ShiftQBus(15) or ShiftQBus(14) or ShiftQBus(13) or ShiftQBus(12)) or
                   (Intensity1 and ShiftQBus(11)) or
                   (Intensity2 and ShiftQBus(10)) or
                   (Intensity3 and ShiftQBus(9)) or
                   (Intensity4 and ShiftQBus(8)) or
                   (Intensity5 and ShiftQBus(7)) or
                   (Intensity6 and ShiftQBus(6)) or
                   (Intensity7 and ShiftQBus(5));
end architecture;

El montaje se ha implementado sobre un CPLD MAX II de Altera, usando leds blancos de alta luminosidad y montándolos luego sobre una base de cartón duro con la típica forma de estrella de navidad.





El código fuente está disponible en la sección soft. ¡Feliz Navidad y feliz 2021!

Comentarios 
Lo sentimos. No se permiten nuevos comentarios después de 90 días.