VHDL代码帮助 - 将整数分成几部分

时间:2014-03-07 13:41:04

标签: vhdl fpga

我有这个代码

Process(counter)
begin
case counter is
when 0 => countertonumber <= "11000000";  -- 0
when 1 => countertonumber <= "11111001" ; -- 1
when 2 => countertonumber <= "10100100" ; -- 2
when 3 => countertonumber <= "10110000" ; -- 3
when 4 => countertonumber <= "10011001" ; -- 4
when 5 => countertonumber <= "10010010" ; -- 5
when 6 => countertonumber <= "10000011" ; -- 6
when 7 => countertonumber <= "11111000" ; -- 7
when 8 => countertonumber <= "10000000" ; -- 8
when 9 => countertonumber <= "10010000" ; -- 9  
when others => 
end case;
end process;

这段代码对于我的程序工作至关重要(在4 * 7段diplay上显示数字)。问题是Counter的Integer值从0到9999,我宁愿不写所有9999的可能性。 是否可以检查每个整数,从而使用它检查它应该写入引脚的值。

如果counter = 9999, 然后我可以在我的计数器值中为每个值切换大小写..

我对如何在VHDL中有效地做到这一点感到有点迷失......

完整的代码和我的想法。

   ----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    23:52:28 03/05/2014 
-- Design Name: 
-- Module Name:    Main - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;




entity Main is
PORT(
        CLK: in std_logic;
    --  LED: out std_logic_vector (7 downto 0);
        Switch: in std_logic_vector(7 downto 0);
        Segment: out std_logic_vector (7 downto 0); 
        AN: out std_logic_vector (3 downto 0) 
        );
end Main;


architecture Behavioral of Main is
signal counter_1000:     integer range 0 to 10;
signal counter_100:          integer range 0 to 10;
signal counter_10:       integer range 0 to 10;
signal counter_1:            integer range 0 to 10;
signal prescaler:  integer range 0 to 50000000;
signal limit:        integer range 0 to 50000000;
signal countertonumber: std_logic_vector (7 downto 0);

begin
ScalerChoice: Process(switch)
begin
CASE Switch IS
when "00000001" => limit <= 50000000/1; -- 1 Hz;
when "00000010" => limit <= 50000000/3; -- 3 HZ
When "00000100" => limit <= 50000000/10; -- 10 Hz
when "00001000" => limit <= 50000000/25; -- 25 Hz
When "00010000" => limit <= 50000000/50; -- 50 Hz; 
when "00100000" => limit <= 50000000/100; -- 100 hz
when others => limit <=      50000000/50000000; -- 50 MHz
end case;
end process;

CounterProcess: process(CLK,Switch)
begin
if rising_edge(CLK) then
    if prescaler < limit then 
        prescaler <= prescaler + 1;
        else
            prescaler <= 0; 
            counter_1 <= counter_1 + 1;

                if (counter_1 > 9) then
                counter_1 <= 0;
                counter_10 <= counter_10 + 1;

                    if (counter_10 > 9) then
                    counter_10 <= 0;
                    counter_100 <= counter_100 + 1;

                        if (counter_100 > 9) then
                        counter_100 <= 0;
                        counter_1000 <= counter_1000 + 1;

                            if (counter_1000 > 9) then
                            counter_100 <= 0;
                            counter_10 <= 0;
                            counter_1 <= 0;
                            counter_1000 <= 0;
                            end if;
                        end if;
                    end if;
                end if; 
        end if;
end if;
end process;


Process(counter_1, Counter_10,Counter_100,Counter_1000,clk)
begin
if rising_edge(cLK) then
    An <= "1110";
    case counter_1 is
    when 0 => countertonumber <= "11000000";  -- 0
    when 1 => countertonumber <= "11111001" ; -- 1
    when 2 => countertonumber <= "10100100" ; -- 2
    when 3 => countertonumber <= "10110000" ; -- 3
    when 4 => countertonumber <= "10011001" ; -- 4
    when 5 => countertonumber <= "10010010" ; -- 5
    when 6 => countertonumber <= "10000011" ; -- 6
    when 7 => countertonumber <= "11111000" ; -- 7
    when 8 => countertonumber <= "10000000" ; -- 8
    when others => countertonumber <= "11000000" ; -- 9 
    end case;

    case counter_10 is
    when 0 => countertonumber <= "11000000";  -- 0
    when 1 => countertonumber <= "11111001" ; -- 1
    when 2 => countertonumber <= "10100100" ; -- 2
    when 3 => countertonumber <= "10110000" ; -- 3
    when 4 => countertonumber <= "10011001" ; -- 4
    when 5 => countertonumber <= "10010010" ; -- 5
    when 6 => countertonumber <= "10000011" ; -- 6
    when 7 => countertonumber <= "11111000" ; -- 7
    when 8 => countertonumber <= "10000000" ; -- 8
    when others => countertonumber <= "11000000" ; -- 9 
    end case;
    segment <= countertonumber;


    An <= "1011";
    case counter_100 is
    when 0 => countertonumber <= "11000000";  -- 0
    when 1 => countertonumber <= "11111001" ; -- 1
    when 2 => countertonumber <= "10100100" ; -- 2
    when 3 => countertonumber <= "10110000" ; -- 3
    when 4 => countertonumber <= "10011001" ; -- 4
    when 5 => countertonumber <= "10010010" ; -- 5
    when 6 => countertonumber <= "10000011" ; -- 6
    when 7 => countertonumber <= "11111000" ; -- 7
    when 8 => countertonumber <= "10000000" ; -- 8
    when others => countertonumber <= "11000000" ; -- 9 
    end case;
    segment <= countertonumber;


    An <= "0111";
    case counter_1000 is
    when 0 => countertonumber <= "11000000";  -- 0
    when 1 => countertonumber <= "11111001" ; -- 1
    when 2 => countertonumber <= "10100100" ; -- 2
    when 3 => countertonumber <= "10110000" ; -- 3
    when 4 => countertonumber <= "10011001" ; -- 4
    when 5 => countertonumber <= "10010010" ; -- 5
    when 6 => countertonumber <= "10000011" ; -- 6
    when 7 => countertonumber <= "11111000" ; -- 7
    when 8 => countertonumber <= "10000000" ; -- 8
    when others => countertonumber <= "11000000" ; -- 9 

    segment <= countertonumber;
    end case;
end if;
end process;



end Behavioral;

4 个答案:

答案 0 :(得分:1)

对于任何硬件问题,首先绘制硬件图片,然后编写代码。

我在您的代码中看到以下内容,一次只选择一个阳极,并将数字多路复用到阴极线上。我在代码中看不到清楚的是你如何选择特定的阳极和计数器(i)。根据您的“想法”代码,最后一个分配获胜,您最终选择counter(3)和AN&lt; =“1110”;总是

我建议您将问题的这一部分分解为两部分。第一部分选择选择哪个阳极和哪个计数器。第二部分解码活动计数器并将该值放在阴极上(countertonumber)。如果你这样做,你只需要编写(和调试)一个case语句来解码计数器。

您缺少的部分是阳极和活动计数器的选择。我用了一个额外的计数器来做到这一点。在完美的板上,计算0到3可以正常工作。在我使用的电路板上,连接到阳极的晶体管很慢,所以我使用值0到7.值0,阳极0打开而计数器(0)是活动计数器。值1,所有阳极关闭,计数器(0)是活动计数器。值1,阳极1打开,计数器(1)是活动计数器。值2,所有阳极关闭,计数器(1)是活动计数器。等等。

用于解码活动计数器的代码只是您在上面编写的代码。

如果使用多个进程,请使用有效计数器值的信号。如果使用单个进程,请使用变量作为活动计数器值。

答案 1 :(得分:1)

我认为你在相同的CLK边缘有多个计数器分配,加上在0-9范围内声明的计数器不能被测试为9以上。这是你的过程稍微重新审视。我没有测试,但我认为它可以完成你的任务。

   CounterProcess: process(CLK,Switch)
   begin
      if rising_edge(CLK) then
         if prescaler < limit then
            prescaler <= prescaler + 1;
         else
            prescaler <= 0;
            if (counter_1 < 9) then
               counter_1 <= counter_1 + 1;
            else
               counter_1 <= 0;
               if (counter_10 < 9) then
                  counter_10 <= counter_10 + 1;
               else
                  counter_10 <= 0;
                  if (counter_100 < 9) then
                     counter_100 <= counter_100 + 1;
                  else
                     counter_100 <= 0;
                     if (counter_1000 < 9) then
                        counter_1000 <= counter_100 + 1;
                     else
                        counter_1000 <= 0;
                        counter_1    <= 0;
                        counter_10   <= 0;
                        counter_100  <= 0;
                     end if;
                  end if;
               end if;
            end if;
         end if;
      end if;
   end process;

enter code here

enter image description here

enter image description here

enter image description here

答案 2 :(得分:0)

如果您担心性能,可以考虑将计数值保存在4个单独的数字中,从0到9,而不是取消单个大整数。您可以为此目的使用变量或信号。当其中一个数字溢出时,您应该增加下一个数字。要生成显示输出,您只需为每个数字复制相同的转换逻辑。您可以使用函数或单独的实体来避免重复代码。

如果你不担心性能,你可以看看我写的一个小型库。检查Decimal number on 7 segment display的答案。

答案 3 :(得分:0)

执行此操作的最佳方法取决于计数器值的表示。

如果它表示为4个十进制数字的数组(即使用BCD算术),那么您只需依次处理每个数字。

即使你的计数器是二进制的,你会发现除以10并计算余数并不是一个不可能的昂贵操作;特别是如果您不需要在单个时钟周期内得到结果:执行重复减法的状态机每个数字只需要10个时钟周期。按照你更新显示器的速度,我怀疑这种延迟很重要!

我会使用常量数组来显示我的显示解码值,并用数组中的简单查找替换每个大型case语句。

例如:

type Count_Value is natural range 0 to 9999;
type Digit is natural range 0 to 9;
type Digits is (thousands, hundreds, tens, units);
type Display_Data is std_logic_vector(7 downto 0);

constant Divisors : array (Digits) of Count_Value := (1000, 100, 10, 1);
constant Lookup   : array (Digit) of Display_Data := 
                    ("11000000", "11111001", ... 10010000");

signal Display : array(Digits) of Display_Data;
signal Count : Count_Value;
signal Start : std_logic;

...

Update : process (Clock) is
   type     State_Type is (idle, processing);
   variable State : State_Type;
   variable This_Digit : Digits;
   variable This_Value : Digit;
   variable Remaining  : Count_Value;
begin
   if rising_edge(Clock) then
      if State = idle then   -- convert when asked
         if Start = '1' then
            Remaining  := Count;
            This_Digit := thousands;
            This_Value := 0;
            State      := processing;
         end if;
      else
         -- process current digit
         if Remaining < Divisors(This_Digit) then
            -- finish this digit
            Display(This_Digit) <= Lookup(This_Value);
            -- done?
            if This_Digit = Units then
               State := idle;
            else
               -- move to next digit
               This_Value := 0;
               This_Digit := Digits'succ(This_Digit);
            end if;            
         else
            Remaining  := Remaining - Divisors(This_Digit);
            This_Value := This_Value + 1;
         end if;
      end if; 
   end if;
end process; 

编辑:这个例子是一个过程,当Start被置位时,它将整数Count分成四个独立的数字,并将这些数字的7段解码值输出到Display信号上。它可以很容易地适用于驱动多路复用显示器,或者添加诸如信号之类的功能,以指示何时完成生成显示值。

我将保留可选功能,例如前导零消隐,或者在处理完成后,如果Start仍然很高,则避免重新触发。