FPGA数字钟系统设计——VHDL语言

一、设计任务与要求

设计一个数字时钟系统,该系统应包含准确的计时、直观的显示、方便的校时和复位功能。采用EDA自顶向下的设计方法,在Quartus II环境中,结合原理图和VHDL文本混合输入,完成数字时钟系统的整体设计、各功能模块的程序编写、仿真验证,并在FPGA实验开发板上实现。系统需实现时、分、秒的计时,通过6个LED七段数码管显示时间,支持通过按键进行小时和分钟的单独调整,以及通过按键进行系统复位。

二、数字钟系统设计分析

在数字钟系统设计中,我们采用了自顶向下的方法,将系统划分为多个子模块以实现所需功能。主要模块设计概述如下:

1、分频器模块:用于降低时钟频率,生成1Hz的时钟信号和1KHz的刷新信号,分别用于时间计量和数码管刷新。

2、信号分配模块:负责将1Hz时钟信号和复位信号分发至秒、分、时计时器,确保同步计时和复位。

3、计时器模块:采用24进制和60进制计数器分别记录小时、分钟和秒数,通过进位信号实现连续计时。

4、数据选择器与消抖模块:选择时间调整模式,并使用D触发器型电路消除按键抖动,确保输入信号的稳定性。

5、数码管译码器模块:将计时器的二进制输出转换为数码管可显示的编码,并行输出到显示模块。

6、显示与提醒模块:通过1KHz刷新信号驱动数码管动态显示时间,同时实现闹钟提醒功能,当时间达到预设值时触发蜂鸣器。

7、模块整合:通过原理图设计连接各模块,优化信号传输路径,形成完整的数字钟系统。

三、管脚配置及程序下载硬件验证

1、管脚配置

在FPGA设计流程中,管脚配置是确保设计正确映射到物理硬件的关键步骤。针对选用的FPGA开发板型号(EP4CE10F17C8),进行了精确的管脚分配。

(1)了解开发板资源:查阅FPGA开发板的用户手册文档,详细了解了开发板上的各种资源。根据数字钟系统的设计需求,我们规划了所需使用的IO引脚,包括用于连接数码管显示的时间显示引脚、用于接收按键输入的引脚等。

(2)Quartus II环境下的管脚分配:在明确资源规划后,打开了Quartus II软件,在项目中进行了管脚配置。通过软件提供的图形化界面,逐一将VHDL代码中定义的信号与实际硬件的引脚进行对应。

2、程序下载硬件验证

在完成管脚配置后,将VHDL代码编译生成的二进制文件(如“MARQUEE.sof”)通过FPGA开发板的下载工具(如USB-Blaster)下载到FPGA开发板中,进行硬件验证。

(1)时间显示验证:在正常运行状态下,观察数字钟是否能够准确无误地显示当前的时间,包括小时、分钟和秒数。通过长时间运行和多次观察,验证了时间显示的准确性,确保每个时间单位的更新都是准确无误的。

(2)复位功能验证:按下“复位”键,数字钟迅速且完全地重置为初始状态。这时所有时间单位(小时、分钟、秒)都归零。当松开“复位”键时,系统从初始时间开始计时。

(3)闹钟功能验证:在闹钟功能验证环节,设定了特定的时间(如“00:00:00”和“12:00:00”)作为触发蜂鸣器响起的条件。当达到这些特定时间时,观察到蜂鸣器按预期响起2秒,从而验证了闹钟功能的实现。

(4)时间调分功能验证:按下“调分”键。当按下“调分”键时,数字钟的分钟显示将按照预设的1Hz速度递增。当松开“调分”键,时间又按照正常时间开始进行计时。

(5)时间调时功能验证:按下“调时”键。当按下“调时”键时,数字钟的小时显示将按照预设的1Hz速度递增。当松开“调时”键,时间又按照正常时间开始进行计时。

三、代码与原理图连接

1、CLOCKDIVIDER:

LIBRARY IEEE;    
USE IEEE.STD_LOGIC_1164.ALL;    
  
ENTITY CLOCKDIVIDER IS    
    PORT (     
        CLK_IN  : IN  STD_LOGIC;    
        CLK_1KHZ : OUT STD_LOGIC;    
        CLK_1HZ  : OUT STD_LOGIC    
    );    
END CLOCKDIVIDER;    
  
ARCHITECTURE BEHAVIORAL OF CLOCKDIVIDER IS    
    SIGNAL COUNT_1KHZ : INTEGER RANGE 0 TO 24999 := 0;    
    SIGNAL COUNT_1HZ  : INTEGER RANGE 0 TO 24999999 := 0;    
    SIGNAL TEMP_1KHZ  : STD_LOGIC := '0';    
    SIGNAL TEMP_1HZ   : STD_LOGIC := '0';    
BEGIN     
    PROCESS(CLK_IN)    
    BEGIN    
        IF CLK_IN = '1' AND CLK_IN'EVENT THEN    
            IF COUNT_1KHZ = 24999 THEN    
                COUNT_1KHZ <= 0;    
                TEMP_1KHZ <= NOT TEMP_1KHZ;    
            ELSE    
                COUNT_1KHZ <= COUNT_1KHZ + 1;    
            END IF;    
        END IF;    
    END PROCESS;    
    
    CLK_1KHZ <= TEMP_1KHZ;    
      
    PROCESS(CLK_IN)    
    BEGIN    
        IF CLK_IN = '1' AND CLK_IN'EVENT THEN   
            IF COUNT_1HZ = 24999999 THEN    
                COUNT_1HZ <= 0;    
                TEMP_1HZ <= NOT TEMP_1HZ;    
            ELSE    
                COUNT_1HZ <= COUNT_1HZ + 1;    
            END IF;    
        END IF;    
    END PROCESS;    
    
    CLK_1HZ <= TEMP_1HZ;    
    
END BEHAVIORAL;

2、MUX_TWO_ONE:

LIBRARY IEEE;  
USE IEEE.STD_LOGIC_1164.ALL;  
USE IEEE.STD_LOGIC_UNSIGNED.ALL; 

ENTITY MUX_TWO_ONE IS
PORT(
	 KEY       : IN STD_LOGIC;  -- 选择信号
    CLK_1HZ  : IN  STD_LOGIC;  -- 1HZ时钟输入
    CLK_QOUT  : IN  STD_LOGIC; -- 时钟输入
    CLK_OUT    : OUT STD_LOGIC -- 输出时钟
);
END MUX_TWO_ONE; 

ARCHITECTURE MUX OF MUX_TWO_ONE IS
    SIGNAL D1 : STD_LOGIC:='1';
	 SIGNAL D2 : STD_LOGIC:='1';
	 SIGNAL D3 : STD_LOGIC:='1';
    SIGNAL OUT_KEY : STD_LOGIC; 
BEGIN
    P1: PROCESS(CLK_1HZ)  
    BEGIN  
	 IF CLK_1HZ'EVENT AND CLK_1HZ = '1' THEN 
		D1<=KEY;
		D2<=D1;
		D3<=D2;
	 END IF;
		OUT_KEY<=D1 OR D2 OR D3;
    END PROCESS P1;

    P2:PROCESS(OUT_KEY)
    BEGIN
    IF OUT_KEY = '0' THEN
		CLK_OUT <= CLK_1HZ;
    ELSE
		CLK_OUT <= CLK_QOUT;
    END IF;
    END PROCESS P2;
END MUX;

3、SPLITTER_ONE_THREE:

LIBRARY IEEE;  
USE IEEE.STD_LOGIC_1164.ALL;  
USE IEEE.STD_LOGIC_UNSIGNED.ALL; 

ENTITY SPLITTER_ONE_THREE IS
PORT(
    INPUT  : IN  STD_LOGIC;    -- 输入
    OUTPUTONE  : OUT  STD_LOGIC;    -- 输出1
    OUTPUTTWO   : OUT STD_LOGIC;    -- 输出2
    OUTPUTTHREE    : OUT STD_LOGIC -- 输出3
);
END SPLITTER_ONE_THREE; 

ARCHITECTURE SPLITTER OF SPLITTER_ONE_THREE IS    
BEGIN
PROCESS(INPUT)
BEGIN
IF INPUT='1' THEN
	OUTPUTONE<='1';
	OUTPUTTWO<='1';
	OUTPUTTHREE<='1';
	ELSE
		OUTPUTONE<='0';
	OUTPUTTWO<='0';
	OUTPUTTHREE<='0';
	END IF;
	END PROCESS;
END SPLITTER;

4、clock_display_24:

library ieee;  
use ieee.std_logic_1164.all;  
use ieee.numeric_std.all;  
  
entity clock_display_24 is  
    Port (  
        seconds : in  std_logic_vector(4 downto 0); -- 输入的秒数(0-59)  
        seg_ten : out std_logic_vector(6 downto 0); -- 十位数码管段  
        seg_one : out std_logic_vector(6 downto 0));  -- 个位数码管段   
end clock_display_24;  
architecture Behavioral of clock_display_24 is  
    -- 七段数码管译码函数  
    function seven_seg_decode(num : integer range 0 to 9) return std_logic_vector is  
        variable seg : std_logic_vector(6 downto 0);  
    begin  
        case num is  
            when 0 => seg := "1000000"; -- A到G(DP省略)  
            when 1 => seg := "1111001";  
				when 2 => seg := "0100100"; 
				when 3 => seg := "0110000"; 
				when 4 => seg := "0011001"; 
				when 5 => seg := "0010010"; 
				when 6 => seg := "0000010"; 
				when 7 => seg := "1111000"; 
				when 8 => seg := "0000000"; 
            when 9 => seg := "0010000";  
            when others => seg := "1111111"; -- 错误指示  
        end case;  
        return seg;  
    end function;  
  
    -- 声明变量来存储十位和个位的值  
    signal ten_val, one_val : integer range 0 to 9;  
  
begin  
    process(seconds)  
    begin  
            -- 计算十位 
            ten_val <= to_integer(unsigned(seconds)) / 10;  
            -- 调用译码函数并更新输出  
            seg_ten <= seven_seg_decode(ten_val);    
    end process;    
    process(seconds)  
    begin  
            -- 计算个位  
            one_val <= to_integer(unsigned(seconds)) mod 10;  
      
            -- 调用译码函数并更新输出   
            seg_one <= seven_seg_decode(one_val);  
    end process;  
end Behavioral;

5、CLOCK_24:

LIBRARY IEEE;  
USE IEEE.STD_LOGIC_1164.ALL;  
USE IEEE.STD_LOGIC_UNSIGNED.ALL; 
  
ENTITY CLOCK_24 IS
PORT(
    CLK  : IN  STD_LOGIC;    -- 时钟输入
    RST  : IN  STD_LOGIC;    -- 重置输入
    CLK_M    : OUT STD_LOGIC_VECTOR(4 DOWNTO 0) -- 当前时间
);
END CLOCK_24; 
  
ARCHITECTURE CLOCK2 OF CLOCK_24 IS    
  SIGNAL TEM_CLK_M : STD_LOGIC_VECTOR(4 DOWNTO 0) := (OTHERS => '0');
BEGIN
  PROCESS(CLK, RST)
  BEGIN
    IF RST = '0' THEN
      TEM_CLK_M <= (OTHERS => '0');
    ELSIF CLK'EVENT AND CLK = '1' THEN
        IF TEM_CLK_M = "11000" THEN
          TEM_CLK_M <= (OTHERS => '0');
        ELSE
          TEM_CLK_M <= TEM_CLK_M + 1;
        END IF;
      END IF;
  END PROCESS;
  CLK_M <= TEM_CLK_M;  
END CLOCK2;

6、CLOCK_60:

LIBRARY IEEE;  
USE IEEE.STD_LOGIC_1164.ALL;  
USE IEEE.STD_LOGIC_UNSIGNED.ALL; 
  
ENTITY CLOCK_60 IS
PORT(
    CLK  : IN  STD_LOGIC;    -- 时钟输入
    RST  : IN  STD_LOGIC;    -- 重置输入
    QOUT     : OUT STD_LOGIC;    -- 进位输出信号
    CLK_M    : OUT STD_LOGIC_VECTOR(5 DOWNTO 0) -- 当前时间
);
END CLOCK_60; 
  
ARCHITECTURE CLOCK1 OF CLOCK_60 IS    
  SIGNAL TEM_CLK_M : STD_LOGIC_VECTOR(5 DOWNTO 0) := (OTHERS => '0');
BEGIN
  PROCESS(CLK, RST)
  BEGIN
    IF RST = '0' THEN
      TEM_CLK_M <= (OTHERS => '0');
      QOUT <= '0';
    ELSIF CLK'EVENT AND CLK = '1' THEN
        IF TEM_CLK_M = "111011" THEN
          QOUT <= '1';
          TEM_CLK_M <= (OTHERS => '0');
        ELSE
          TEM_CLK_M <= TEM_CLK_M + 1;
          QOUT <= '0';
        END IF;
      END IF;
  END PROCESS;
  CLK_M <= TEM_CLK_M;  
END CLOCK1;

7、clock_display :

library ieee;  
use ieee.std_logic_1164.all;  
use ieee.numeric_std.all;  
  
entity clock_display is  
    Port (  
        seconds : in  std_logic_vector(5 downto 0); -- 输入的秒数(0-59)  
        seg_ten : out std_logic_vector(6 downto 0); -- 十位数码管段  
        seg_one : out std_logic_vector(6 downto 0));  -- 个位数码管段  

end clock_display;  
architecture Behavioral of clock_display is  
    -- 七段数码管译码函数  
    function seven_seg_decode(num : integer range 0 to 9) return std_logic_vector is  
        variable seg : std_logic_vector(6 downto 0);  
    begin  
        case num is  
            when 0 => seg := "1000000"; -- A到G(DP省略)  
            when 1 => seg := "1111001";  
				when 2 => seg := "0100100"; 
				when 3 => seg := "0110000"; 
				when 4 => seg := "0011001"; 
				when 5 => seg := "0010010"; 
				when 6 => seg := "0000010"; 
				when 7 => seg := "1111000"; 
				when 8 => seg := "0000000"; 
            when 9 => seg := "0010000";  
            when others => seg := "1111111"; -- 错误指示  
        end case;  
        return seg;  
    end function;  
  
    -- 声明变量来存储十位和个位的值  
    signal ten_val, one_val : integer range 0 to 9;  
  
begin  
    process(seconds)  
    begin  
            -- 计算十位 
            ten_val <= to_integer(unsigned(seconds)) / 10;  
            -- 调用译码函数并更新输出  
            seg_ten <= seven_seg_decode(ten_val);    
    end process;    
    process(seconds)  
    begin  
            -- 计算个位  
            one_val <= to_integer(unsigned(seconds)) mod 10;  
      
            -- 调用译码函数并更新输出   
            seg_one <= seven_seg_decode(one_val);  
    end process;  
end Behavioral;

8、TUBE:

LIBRARY IEEE;  
USE IEEE.STD_LOGIC_1164.ALL;  
USE IEEE.STD_LOGIC_UNSIGNED.ALL;   
  
ENTITY TUBE IS  
    PORT (  
        CLK            : IN  STD_LOGIC;  
        TUBE_SIX       : IN  STD_LOGIC_VECTOR(6 DOWNTO 0);  
        TUBE_FIVE      : IN  STD_LOGIC_VECTOR(6 DOWNTO 0);  
        TUBE_FOUR      : IN  STD_LOGIC_VECTOR(6 DOWNTO 0);  
        TUBE_THREE     : IN  STD_LOGIC_VECTOR(6 DOWNTO 0);  
        TUBE_TWO       : IN  STD_LOGIC_VECTOR(6 DOWNTO 0);  
        TUBE_ONE       : IN  STD_LOGIC_VECTOR(6 DOWNTO 0);  
        TUBE_NOW       : OUT STD_LOGIC_VECTOR(6 DOWNTO 0);  
        TIME_CLOCK     : OUT STD_LOGIC;  
        EN             : OUT STD_LOGIC_VECTOR(5 DOWNTO 0)  
    );  
END TUBE;  
  
ARCHITECTURE ONE OF TUBE IS  
    SIGNAL TEM_EN            : STD_LOGIC_VECTOR(5 DOWNTO 0) := "011111";  
    SIGNAL TEM_TIME_CLOCK    : STD_LOGIC := '1';  
    SIGNAL FLAG              : STD_LOGIC := '0';  
    SIGNAL TEM_TUBE_SIX      : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";  
    SIGNAL TEM_TUBE_FIVE     : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";  
    SIGNAL TEM_TUBE_FOUR     : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";  
    SIGNAL TEM_TUBE_THREE    : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";  
    SIGNAL TEM_TUBE_TWO      : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";  
    SIGNAL TEM_TUBE_ONE      : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";  
BEGIN 
P1: PROCESS(CLK)  
BEGIN  
    IF CLK'EVENT AND CLK = '1' THEN  
        TEM_EN <= TEM_EN(4 DOWNTO 0) & TEM_EN(5);  
        EN <= TEM_EN;  
    END IF;  
END PROCESS P1;  
  
P2: PROCESS(TEM_EN, TUBE_ONE, TUBE_TWO, TUBE_THREE, TUBE_FOUR, TUBE_FIVE, TUBE_SIX)  
BEGIN  
    CASE TEM_EN IS  
        WHEN "111101" => TUBE_NOW <= TUBE_ONE;  
        WHEN "111011" => TUBE_NOW <= TUBE_TWO;  
        WHEN "110111" => TUBE_NOW <= TUBE_THREE;  
        WHEN "101111" => TUBE_NOW <= TUBE_FOUR;  
        WHEN "011111" => TUBE_NOW <= TUBE_FIVE;  
        WHEN "111110" => TUBE_NOW <= TUBE_SIX;  
        WHEN OTHERS  => TUBE_NOW <= (OTHERS => '0');  
    END CASE;  
END PROCESS P2;
P3: PROCESS(CLK)  
VARIABLE COUNTER : INTEGER RANGE 0 TO 1000;  
BEGIN  
    TEM_TUBE_SIX <= TUBE_SIX;  
    TEM_TUBE_FIVE <= TUBE_FIVE;  
    TEM_TUBE_FOUR <= TUBE_FOUR;  
    TEM_TUBE_THREE <= TUBE_THREE;  
    TEM_TUBE_TWO <= TUBE_TWO;  
    TEM_TUBE_ONE <= TUBE_ONE;  
  
    IF (  
        TEM_TUBE_ONE = "1000000" AND TEM_TUBE_TWO = "1000000" AND TEM_TUBE_THREE = "1000000" AND TEM_TUBE_FOUR = "1000000" AND TEM_TUBE_FIVE = "0100100" AND TEM_TUBE_SIX = "1111001"  
    ) THEN  
        COUNTER := 0;  
        TEM_TIME_CLOCK <= '0';  
        FLAG <= '1';  
    ELSIF (  
        TEM_TUBE_ONE = "1000000" AND TEM_TUBE_TWO = "1000000" AND TEM_TUBE_THREE = "1000000" AND TEM_TUBE_FOUR = "1000000" AND TEM_TUBE_FIVE = "1000000" AND TEM_TUBE_SIX = "1000000"  
    ) THEN  
        COUNTER := 0;  
        TEM_TIME_CLOCK <= '0';  
        FLAG <= '1';  
    ELSIF FLAG = '1' THEN  
        IF CLK'EVENT AND CLK = '1' THEN  
            COUNTER := COUNTER + 1;  
        END IF;  
        IF COUNTER = 1000 THEN  
            TEM_TIME_CLOCK <= '1';  
            FLAG <= '0';  
        END IF;  
    END IF;  
END PROCESS P3;  
  
TIME_CLOCK <= TEM_TIME_CLOCK; 
END ONE;

9、原理图连接:

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SkyQi_奇崽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值