Leer el valor decimal de una entrada binaria de 4 bits

1

Soy un novato en el mundo de VHDL, pero parece que tengo lo básico. Cajeros automáticos Estoy trabajando en un proyecto, que me obliga a tomar una entrada binaria de 4 bits (interruptores), leer este valor y convertirlo a valores decimales.

Hasta aquí tengo variables (count_ones, count_tens) que se supone que contienen el valor decimal de la entrada.

Mi código actual es el siguiente:

architecture Behavioral of Seven_Seg_Counter is

    signal      count_ones      :   integer range 0 to 9 := 0;
    signal      count_tens      :   integer range 0 to 9 := 0;
    signal      count_hundreds  :   integer range 0 to 9 := 0;
    signal      count_thousands :   integer range 0 to 9 := 0;
    signal      prescaler       :   integer := 0;
    signal      anode           :   integer range 1 to 4 := 1;
    signal      digit           :   STD_LOGIC_VECTOR(3 downto 0) := "1110";

begin
    Calculate: process (CLK)
        variable        countings           :   integer range 0 to 9 := 0;

    begin
        if rising_edge(CLK) then
            if INPUT(3) = '1' then
                countings := 8;
            else
                countings := 0;
            end if;
            if INPUT(2) = '1' then
                countings := countings + 4;
            else
                countings := 0;
            end if;
            if INPUT(1) = '1' then
                countings := countings + 2;
            else
                countings := 0;
            end if;
            if INPUT(0) = '1' then
                countings := countings + 1;
            else
                countings := 0;
            end if;

            for I in 1 to 9 loop
                if countings > 9 then
                    countings := countings  - 10;
                    count_tens <= count_tens + 1;
                else
                    count_tens <= 0;
                end if;
            end loop;

            for G in 1 to 9 loop
                if countings > 0 then
                    countings := countings - 1;
                    count_ones <= count_ones + 1;
                else
                    count_ones <= 0;
                end if;
            end loop;
        end if;
    end process;

    process (anode, count_thousands, count_hundreds, count_tens, count_ones) -- Bestemmer output som funktion signalerne anode (segmentvælger) og count_XX (den decimale værdi)
    begin
        case anode is
            when 1 => 
                case count_ones is
                                          --abcdefg
                    when 0 => sseg <= "0000001"; -- 0
                    when 1 => sseg <= "1001111"; -- 1
                    when 2 => sseg <= "0010010"; -- 2
                    when 3 => sseg <= "0000110"; -- 3
                    when 4 => sseg <= "1001100"; -- 4
                    when 5 => sseg <= "0100100"; -- 5
                    when 6 => sseg <= "0100000"; -- 6
                    when 7 => sseg <= "0001111"; -- 7
                    when 8 => sseg <= "0000000"; -- 8
                    when 9 => sseg <= "0000100"; -- 9
                end case;
            when 2 => case count_tens is
                                          --abcdefg
                    when 0 => sseg <= "0000001"; -- 0
                    when 1 => sseg <= "1001111"; -- 1
                    when 2 => sseg <= "0010010"; -- 2
                    when 3 => sseg <= "0000110"; -- 3
                    when 4 => sseg <= "1001100"; -- 4
                    when 5 => sseg <= "0100100"; -- 5
                    when 6 => sseg <= "0100000"; -- 6
                    when 7 => sseg <= "0001111"; -- 7
                    when 8 => sseg <= "0000000"; -- 8
                    when 9 => sseg <= "0000100"; -- 9
                end case;
            when 3 => case count_hundreds is
                                          --abcdefg
                    when 0 => sseg <= "0000001"; -- 0
                    when 1 => sseg <= "1001111"; -- 1
                    when 2 => sseg <= "0010010"; -- 2
                    when 3 => sseg <= "0000110"; -- 3
                    when 4 => sseg <= "1001100"; -- 4
                    when 5 => sseg <= "0100100"; -- 5
                    when 6 => sseg <= "0100000"; -- 6
                    when 7 => sseg <= "0001111"; -- 7
                    when 8 => sseg <= "0000000"; -- 8
                    when 9 => sseg <= "0000100"; -- 9
                end case;
            when 4 =>  case count_thousands is
                                          --abcdefg
                    when 0 => sseg <= "0000001"; -- 0
                    when 1 => sseg <= "1001111"; -- 1
                    when 2 => sseg <= "0010010"; -- 2
                    when 3 => sseg <= "0000110"; -- 3
                    when 4 => sseg <= "1001100"; -- 4
                    when 5 => sseg <= "0100100"; -- 5
                    when 6 => sseg <= "0100000"; -- 6
                    when 7 => sseg <= "0001111"; -- 7
                    when 8 => sseg <= "0000000"; -- 8
                    when 9 => sseg <= "0000100"; -- 9
                end case;
        end case;
    end process;

    process (anode)
    begin
        case anode is
            when 1 => digit <= "1110";
            when 2 => digit <= "1101";
            when 3 => digit <= "1011";
            when 4 => digit <= "0111";
        end case;
    end process;

    segmentselect <= digit;
    LED_OUT <= INPUT;
end Behavioral;

Mi idea es que almacene el valor binario (mirando a un lado los complementos de 1 y 2) en los recuentos de variables (que funcionan bien en una simulación). La siguiente parte es, donde realmente encuentro el valor de los conteos, y almaceno su dígito más a la derecha en la señal count_ones (ones), y el dígito más a la izquierda (decenas) en la señal count_tens. Por alguna razón desconocida, mi forma de encontrar las unidades y las decenas no funciona bien con esos bucles. Tal vez entendí mal cómo usarlo para bucles.

¿Alguno de ustedes podría ayudarme? Realmente lo apreciaría.

Los bucles son difíciles de hecho. La cuestión es que una entrada de 4 bits es solo el comienzo, me gustaría poder leer más, así que si puedo aprender el método básico con solo 4 bits, sería increíble.

Bueno, la señal de count_ones es para los unos, y el count_tens es para las decenas de la entrada, así que no estoy muy seguro de obtener, cómo to_integer (unsigned (INPUT)); va a funcionar, así que obtengo un valor decimal de 0 a 9 en count_ones o count_tens.

El método de resta al que hace referencia, creo, he intentado implementar eso en mis bucles, que no funcionan como se esperaba.

    
pregunta Jacob Overgaard

2 respuestas

1

Los bucles en HDL son difíciles de usar de manera sintetizable. Recomendaría simplemente leer los bits de entrada como un número binario, comparar con 9, si es mayor restar 10.

    
respondido por el alex.forencich
1

Solución 1:
El algoritmo de doble dabble . Electronics.StackExchange enumera muchas preguntas y respuestas para este tema :

StackOverflow también está lleno de resultados .

Solución 2
Utilizando una matriz sistólica de conversiones de dígitos.

Convirtamos una entrada binaria n -bit en dígitos m . Cada elemento sistólico tiene una entrada Clock y Reset , así como una señal de 1 bit Shift_in . Genera un BCD de 4 bits codificado Digit y una señal Shift_out (también conocido como desbordamiento).

Esta es la declaración de puerto del elemento:

subtype T_BCD : UNSIGNED(3 downto 0);

entity arith_convert_bin2bcd_element is
  port (
    Clock      : IN  STD_LOGIC;
    Reset      : IN  STD_LOGIC;

    Shift_en   : IN  STD_LOGIC;
    Shift_in   : IN  STD_LOGIC;
    Shift_out  : OUT STD_LOGIC;
    BCD        : OUT T_BCD
  );
end;

¿Cómo funciona?

En cada operación de turno, calcula:
\ $ Dígito = Dígito * 2 + Shift_ {in} \ $

\ $ Shift_ {out} = \ begin {cases} 1 & \ text {when} \, \, (Digit \ ge 10) \\ 0 & else \ end {cases} \ $

\ $ Digit = \ begin {cases} Digit-10 & \ text {when} \, \, (Digit \ ge 10) \\ Digit & else \ end {cases} \ $

architecture rtl of arith_convert_bin2bcd_element is
  signal Digit_ext  : UNSIGNED(T_BCD'length downto 0);
  signal Digit_ov   : STD_LOGIC;
  signal Digit_d    : T_BCD        := "0000";
begin

  Digit_ext  <= Digit_d & Shift_in;
  Digit_ov  <= to_sl(Digit_ext > 9);
  Shift_out  <= Digit_ov;-- when rising_edge(Clock);    -- register overflow

  process(Clock)
  begin
    if rising_edge(Clock) then
      if (Reset = '1') then
        Digit_d    <= "0000";
      elsif (Shift_en = '1') then
        if (Digit_ov = '0') then
          Digit_d  <= Digit_ext(Digit_d'range);
        else
          Digit_d  <= resize(Digit_ext - 10, Digit_d'length);
        end if;
      end if;
    end if;
  end process;

  BCD <= Digit_d;
end;

Ahora puede combinar tantos elementos como sea necesario para convertir un número binario. ¿Qué se necesita para esta tarea?

  • un FSM con 3-4 estados: inactivo, [complemento], convertir, completo
    el complemento solo es necesario si la entrada puede ser negativa
  • un contador que cuenta para n operaciones de cambio
  • un registro de entrada / salida en paralelo, que se desplaza o gira a la izquierda (al bit más alto)
  • una declaración de generación, que genera m elemento instancias

Y aquí está el cableado de la matriz sistólica y la lógica de control:

entity arith_convert_bin2bcd is
  generic (
    IS_SIGNED     : BOOLEAN     := FALSE;
    BITS          : POSITIVE    := 8;
    DIGITS        : POSITIVE    := 3
  );
  port (
    Clock         : IN  STD_LOGIC;
    Reset         : IN  STD_LOGIC;

    Start         : IN  STD_LOGIC;
    Complete      : OUT STD_LOGIC;

    Binary        : IN  STD_LOGIC_VECTOR(BITS - 1 DOWNTO 0);
    BCDDigits     : OUT T_BCD_VECTOR(DIGITS - 1 DOWNTO 0);
    Sign          : OUT STD_LOGIC
  );
end;

architecture rtl of arith_convert_bin2bcd is
  type T_STATE is (ST_IDLE, ST_CPL, ST_CONVERT, ST_COMPLETE);

  signal State      : T_STATE    := ST_IDLE;
  signal NextState  : T_STATE;

  signal Digit_Shift_en   : STD_LOGIC;
  signal Digit_Shift_in   : STD_LOGIC_VECTOR(DIGITS downto 0);

  signal Binary_en        : STD_LOGIC;
  signal Binary_cpl       : STD_LOGIC;
  signal Binary_rl        : STD_LOGIC;
  signal Binary_d         : STD_LOGIC_VECTOR(BITS - 1 downto 0)      := (others => '0');
  signal Binary_Sign      : STD_LOGIC;

  signal Sign_d           : STD_LOGIC                                := '0';

  signal ShiftCounter_rst : STD_LOGIC;
  signal ShiftCounter_eq  : STD_LOGIC;
  signal ShiftCounter_s   : SIGNED(log2ceilnz(BITS - 1) downto 0)    := (others => '0');
begin

  process(Clock)
  begin
    if rising_edge(Clock) then
      if (Reset = '1') then
        State    <= ST_IDLE;
      else
        State    <= NextState;
      end if;
    end if;
  end process;

  process(State, Start, Binary_Sign, ShiftCounter_eq)
  begin
    NextState         <= State;
    Complete          <= '0';

    Binary_en         <= '0';
    Binary_cpl        <= '0';
    Binary_rl         <= '0';

    Digit_Shift_en    <= '0';
    ShiftCounter_rst  <= '1';

    case State is
      when ST_IDLE =>
        if (Start = '1') then
          Binary_en       <= '1';

          if (Binary_Sign = '1') then
            NextState     <= ST_CPL;
          else
            NextState     <= ST_CONVERT;
          end if;
        end if;

      when ST_CPL =>
        Binary_cpl        <= '1';
        NextState         <= ST_CONVERT;

      when ST_CONVERT =>
        Binary_rl         <= '1';
        Digit_Shift_en    <= '1';
        ShiftCounter_rst  <= '0';

        if (ShiftCounter_eq = '1') then
          NextState       <= ST_COMPLETE;
        end if;

      when ST_COMPLETE =>
        Complete          <= '1';
        NextState         <= ST_IDLE;

    end case;
  end process;

  process(Clock)
  begin
    if rising_edge(Clock) then
      if (Reset = '1') then
        Binary_d  <= (others => '0');
      elsif (Binary_en = '1') then
        Binary_d  <= Binary;
        Sign_d    <= '0';
      elsif (Binary_cpl = '1') then
        Binary_d  <= cpl(Binary_d);    -- 2's component
        Sign_d    <= '1';
      elsif (Binary_rl = '1') then
        Binary_d  <= Binary_d(Binary_d'high - 1 downto 0) & Binary_d(Binary_d'high);
      end if;
    end if;
  end process;

  Sign              <= Sign_d;

  Binary_Sign       <= Binary_d(Binary_d'high);
  Digit_Shift_in(0) <= Binary_d(Binary_d'high);

  -- count shift operations from BITS-2 downto -1
  ShiftCounter_s    <= counter_dec(ShiftCounter_s, ShiftCounter_rst, '1', BITS - 2) when rising_edge(Clock);
  ShiftCounter_eq   <= ShiftCounter_s(ShiftCounter_s'high);

  -- generate DIGITS many systolic elements
  genDigits : for i in 0 to DIGITS - 1 generate
   Digit : entity PoC.arith_convert_bin2bcd_element
    port map (
      Clock       => Clock,
      Reset       => Reset,

      Shift_en    => Digit_Shift_en,
      Shift_in    => Digit_Shift_in(i),
      Shift_out   => Digit_Shift_in(i + 1),
      BCD         => BCDDigits(i)
    );
  end generate;
end;

Y aquí hay una simulación (pulsable):

    
respondido por el Paebbels

Lea otras preguntas en las etiquetas