vhdl7我学习得第一个fpga项目——倒计时显示

之前也编写过fpga程序,但是那都相当于一个子程序,我们知道fpga是模块化设计,自顶向下的构造。那么今天学会了第一个fpga项目:倒计时显示。
1.功能:
1)开关控制计数器工作。
当开关作用,led亮并且保持,每隔一秒,计数器开始从16减到0,用数码管显示,并保持。
2.思路:
1)两个分频器,一个给1s钟的倒计时计数,一个用于驱动数码管。
2)一个计数开关,控制倒计时开始
3)数码管译码电路。
3.设计:
1)首先,从顶层把几个模块定义一下,相互之间接下线,有分频器,计数器,显示模块。
顶层设计
这是顶层设计,外部的clk,和key,输出的led和数码管。
内部结构就是:
计时器内部结构通过这个电路图可以很清楚的看到倒计时计数器内部的结构。
那么在连线(编程实现)出现这样几个问题:1.有引脚定义错误,修改的时候,改了component而没有改port map。2.在port map定义时,u1:xianshi port map(…=>…,…=>…);这个结构搞错了。3.对于component可以直接用entity修改得到。直接componet 名字port(… : … ; … : …);end component;
2.当然接线可以使用手动连接。关掉刚刚设计好的top,用new project新建sch…文件,之后把分频器,计时器,显示器统统creat symbol,再点击add symbol就可以啦。之后add wire,add i/o。之后把i/o更改名字。注意端口位数不能改!
一同操作之后就是这个样子:

硬件连接
之后检查一下rtl电路。正确。可以开始写子模块
3.编写子模块
1)分频器:
1.1这个之前讲过。这次犯的错误是把端口放在process中直接not了,这样会报错,说要用inout。那我直接定义signal就好了。
1.2if语句一定是出现在process中的
1.3变量只可以在当前的process中使用,只有signal才可以全局。signa定义不要加in/out!。
1.4最后记得把signal赋值给相应的port
代码:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--ujs-lili
entity fenpinqi1 is
    Port ( clk : in  STD_LOGIC;
           clk1hz : out  STD_LOGIC;
           clk1khz : out  STD_LOGIC);
end fenpinqi1;
architecture Behavioral of fenpinqi1 is
signal clk_1hz : STD_LOGIC;
signal clk_1khz :  STD_LOGIC;
begin
 process(clk)
 variable q:integer range 1 to 2400000:=1;--48mhz,一个周期1/48m,1hz,一个周期1/1,那么1/1/(1/48m)/2,得到半个周期中clk1hz的次数2400000,因为程序中用not得到上升沿。
 variable p:integer range 1 to 24000:=1;--1khz时间快。
 begin
  if q = 2400000 then
   q:=1;
   clk_1hz <= not clk_1hz;
  else
   q:=q+1;
  end if;
  
   if q = 24000 then
   p:=1;
   clk_1khz <= not clk_1khz;
  else
   p:=p+1;
  end if; 
 end process;
   clk1hz <=  clk_1hz;
   clk1khz <= clk_1khz;
end Behavioral;

写完之后先check syntax。但是你想综合那肯定会报错!
2)设计定时器
首先明确“/=”的意思是不等于

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_arith.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
--ujs_lili
entity dingshiqi is
    Port ( clk1hz : in  STD_LOGIC;
           key : in  STD_LOGIC;
     led : out STD_LOGIC;
           data0 : out  STD_LOGIC_VECTOR (3 downto 0);
           data1 : out  STD_LOGIC_VECTOR (3 downto 0));
end dingshiqi;
architecture Behavioral of dingshiqi is
signal cnt0: STD_LOGIC_VECTOR (3 downto 0);
signal cnt1: STD_LOGIC_VECTOR (3 downto 0);
begin
 process(clk1hz,key)
  begin
   if key='1' then
     cnt1<="0001"; 
     cnt0<="0110";--这里用的bcd码,便于显示
     led<='1';
    else
     led<='0';--表示开关作用
     if clk1hz'event and clk1hz='1' then --1s到
      if cnt0/=0 then --如果个位不等于0,个位就可以自减,如果个位等于0,这时候就要看了如果十位为0,那么计数结束,如果十位不为0,那么置十位为0
       cnt0<=cnt0-1;
       else
        if cnt1/=0 then--如果10位不等于0,也就是1,那么就剩下9,8,7,...
         cnt0<="1001";cnt1<=cnt1-1;
         else--如果十位为0,计数结束,因为if是顺序执行的
          cnt0<="0000";cnt1<="0000";led<='1';
        end if;
      end if;
     end if;
   end if;
 end process;
 data0<=cnt0;
 data1<=cnt1;
end Behavioral;

3)显示模块
主要是靠1khz时钟来驱动的,主要用并行。

4)仿真
仿真出现问题:
仿真
问题:1)led没有变化
2)seg没有变化
3)分频电路有问题
原因:
分频电路中出现了两个错误,首先没有判断clk的上升沿,就直接分频了,其次,signal没有初始值,这样修改之后,1khz和1hz看起来一样,肯定还有问题,继续找,发现第三个if写错了,是判断p,我写成了判断q。
故障图:
二分频错误
至于为什么两者之间会有间隔,那应该是fpga执行速度的问题。
更改之后会发现,clk1hz和clk1khz是有变化了,但是很明显1hz是一秒的周期,仿真图上还是不对。发现是clk_period没有修改。所有修改完毕,得到如下的仿真图:
正确的分频器
代码如下:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--ujs-lili
entity ceshifenpin is
    Port ( clk : in  STD_LOGIC;
           clk1hz : out  STD_LOGIC;
           clk1khz : out  STD_LOGIC);
end ceshifenpin;
architecture Behavioral of ceshifenpin is
signal clk_1hz : STD_LOGIC:='0';
signal clk_1khz :  STD_LOGIC:='0';
begin
 process(clk)
 variable q:integer range 1 to 2400000:=1;--48mhz,一个周期1/48m,1hz,一个周期1/1,那么1/1/(1/48m)/2,得到半个周期中clk1hz的次数2400000,因为程序中用not得到上升沿。
 variable p:integer range 1 to 24000:=1;--1khz时间快。
  begin
   if clk'event and clk='1' then
    if q = 2400000 then
     q:=1;
     clk_1hz <= not clk_1hz;
    else
     q:=q+1;
    end if;
    if p = 24000 then--这个地方没有改,应该时p!
     p:=1;
     clk_1khz <= not clk_1khz;
    else
     p:=p+1;
    end if; 
      end if;
  end process;
   clk1hz <=  clk_1hz;
   clk1khz <= clk_1khz;
end Behavioral;

仿真代码:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
--ujs-lili
ENTITY ceshifenpin_tb IS
END ceshifenpin_tb;
ARCHITECTURE behavior OF ceshifenpin_tb IS 
    -- Component Declaration for the Unit Under Test (UUT) 
    COMPONENT ceshifenpin
    PORT(
         clk : IN  std_logic;
         clk1hz : OUT  std_logic;
         clk1khz : OUT  std_logic
        );
    END COMPONENT;
   --Inputs
   signal clk : std_logic := '0';
  --Outputs
   signal clk1hz : std_logic;
   signal clk1khz : std_logic;
  -- Clock period definitions
   constant clk_period : time := 20.8 ns;--10ns是10的-8 
BEGIN 
 -- Instantiate the Unit Under Test (UUT)
   uut: ceshifenpin PORT MAP (
          clk => clk,
          clk1hz => clk1hz,
          clk1khz => clk1khz
        );
   -- Clock process definitions
   clk_process :process
   begin
  clk <= '0';
  wait for clk_period/2;
  clk <= '1';
  wait for clk_period/2;
   end process;
END;

那么把修改好的分频器放入top模块中可以得到如下波形:

整体仿真
从上面可以看出led还是存在问题的,一直是高电平,
后来发现原来是,key没有作用!
再把seg更改之后,看下仿真结果,正确!

事物
6.总结
不知道是不是第六点。完成第一次项目是艰难的,做了得有4h,但是弄对了,还是不错的。尤其时波形仿真那块。任何时候不放弃,总会成功!

发布了20 篇原创文章 · 获赞 4 · 访问量 3956

猜你喜欢

转载自blog.csdn.net/weixin_43475628/article/details/101112741