当前位置:   article > 正文

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

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:

  1. LIBRARY IEEE;
  2. USE IEEE.STD_LOGIC_1164.ALL;
  3. ENTITY CLOCKDIVIDER IS
  4. PORT (
  5. CLK_IN : IN STD_LOGIC;
  6. CLK_1KHZ : OUT STD_LOGIC;
  7. CLK_1HZ : OUT STD_LOGIC
  8. );
  9. END CLOCKDIVIDER;
  10. ARCHITECTURE BEHAVIORAL OF CLOCKDIVIDER IS
  11. SIGNAL COUNT_1KHZ : INTEGER RANGE 0 TO 24999 := 0;
  12. SIGNAL COUNT_1HZ : INTEGER RANGE 0 TO 24999999 := 0;
  13. SIGNAL TEMP_1KHZ : STD_LOGIC := '0';
  14. SIGNAL TEMP_1HZ : STD_LOGIC := '0';
  15. BEGIN
  16. PROCESS(CLK_IN)
  17. BEGIN
  18. IF CLK_IN = '1' AND CLK_IN'EVENT THEN
  19. IF COUNT_1KHZ = 24999 THEN
  20. COUNT_1KHZ <= 0;
  21. TEMP_1KHZ <= NOT TEMP_1KHZ;
  22. ELSE
  23. COUNT_1KHZ <= COUNT_1KHZ + 1;
  24. END IF;
  25. END IF;
  26. END PROCESS;
  27. CLK_1KHZ <= TEMP_1KHZ;
  28. PROCESS(CLK_IN)
  29. BEGIN
  30. IF CLK_IN = '1' AND CLK_IN'EVENT THEN
  31. IF COUNT_1HZ = 24999999 THEN
  32. COUNT_1HZ <= 0;
  33. TEMP_1HZ <= NOT TEMP_1HZ;
  34. ELSE
  35. COUNT_1HZ <= COUNT_1HZ + 1;
  36. END IF;
  37. END IF;
  38. END PROCESS;
  39. CLK_1HZ <= TEMP_1HZ;
  40. END BEHAVIORAL;

2、MUX_TWO_ONE:

  1. LIBRARY IEEE;
  2. USE IEEE.STD_LOGIC_1164.ALL;
  3. USE IEEE.STD_LOGIC_UNSIGNED.ALL;
  4. ENTITY MUX_TWO_ONE IS
  5. PORT(
  6. KEY : IN STD_LOGIC; -- 选择信号
  7. CLK_1HZ : IN STD_LOGIC; -- 1HZ时钟输入
  8. CLK_QOUT : IN STD_LOGIC; -- 时钟输入
  9. CLK_OUT : OUT STD_LOGIC -- 输出时钟
  10. );
  11. END MUX_TWO_ONE;
  12. ARCHITECTURE MUX OF MUX_TWO_ONE IS
  13. SIGNAL D1 : STD_LOGIC:='1';
  14. SIGNAL D2 : STD_LOGIC:='1';
  15. SIGNAL D3 : STD_LOGIC:='1';
  16. SIGNAL OUT_KEY : STD_LOGIC;
  17. BEGIN
  18. P1: PROCESS(CLK_1HZ)
  19. BEGIN
  20. IF CLK_1HZ'EVENT AND CLK_1HZ = '1' THEN
  21. D1<=KEY;
  22. D2<=D1;
  23. D3<=D2;
  24. END IF;
  25. OUT_KEY<=D1 OR D2 OR D3;
  26. END PROCESS P1;
  27. P2:PROCESS(OUT_KEY)
  28. BEGIN
  29. IF OUT_KEY = '0' THEN
  30. CLK_OUT <= CLK_1HZ;
  31. ELSE
  32. CLK_OUT <= CLK_QOUT;
  33. END IF;
  34. END PROCESS P2;
  35. END MUX;

3、SPLITTER_ONE_THREE:

  1. LIBRARY IEEE;
  2. USE IEEE.STD_LOGIC_1164.ALL;
  3. USE IEEE.STD_LOGIC_UNSIGNED.ALL;
  4. ENTITY SPLITTER_ONE_THREE IS
  5. PORT(
  6. INPUT : IN STD_LOGIC; -- 输入
  7. OUTPUTONE : OUT STD_LOGIC; -- 输出1
  8. OUTPUTTWO : OUT STD_LOGIC; -- 输出2
  9. OUTPUTTHREE : OUT STD_LOGIC -- 输出3
  10. );
  11. END SPLITTER_ONE_THREE;
  12. ARCHITECTURE SPLITTER OF SPLITTER_ONE_THREE IS
  13. BEGIN
  14. PROCESS(INPUT)
  15. BEGIN
  16. IF INPUT='1' THEN
  17. OUTPUTONE<='1';
  18. OUTPUTTWO<='1';
  19. OUTPUTTHREE<='1';
  20. ELSE
  21. OUTPUTONE<='0';
  22. OUTPUTTWO<='0';
  23. OUTPUTTHREE<='0';
  24. END IF;
  25. END PROCESS;
  26. END SPLITTER;

4、clock_display_24:

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. use ieee.numeric_std.all;
  4. entity clock_display_24 is
  5. Port (
  6. seconds : in std_logic_vector(4 downto 0); -- 输入的秒数(0-59
  7. seg_ten : out std_logic_vector(6 downto 0); -- 十位数码管段
  8. seg_one : out std_logic_vector(6 downto 0)); -- 个位数码管段
  9. end clock_display_24;
  10. architecture Behavioral of clock_display_24 is
  11. -- 七段数码管译码函数
  12. function seven_seg_decode(num : integer range 0 to 9) return std_logic_vector is
  13. variable seg : std_logic_vector(6 downto 0);
  14. begin
  15. case num is
  16. when 0 => seg := "1000000"; -- A到G(DP省略)
  17. when 1 => seg := "1111001";
  18. when 2 => seg := "0100100";
  19. when 3 => seg := "0110000";
  20. when 4 => seg := "0011001";
  21. when 5 => seg := "0010010";
  22. when 6 => seg := "0000010";
  23. when 7 => seg := "1111000";
  24. when 8 => seg := "0000000";
  25. when 9 => seg := "0010000";
  26. when others => seg := "1111111"; -- 错误指示
  27. end case;
  28. return seg;
  29. end function;
  30. -- 声明变量来存储十位和个位的值
  31. signal ten_val, one_val : integer range 0 to 9;
  32. begin
  33. process(seconds)
  34. begin
  35. -- 计算十位
  36. ten_val <= to_integer(unsigned(seconds)) / 10;
  37. -- 调用译码函数并更新输出
  38. seg_ten <= seven_seg_decode(ten_val);
  39. end process;
  40. process(seconds)
  41. begin
  42. -- 计算个位
  43. one_val <= to_integer(unsigned(seconds)) mod 10;
  44. -- 调用译码函数并更新输出
  45. seg_one <= seven_seg_decode(one_val);
  46. end process;
  47. end Behavioral;

5、CLOCK_24:

  1. LIBRARY IEEE;
  2. USE IEEE.STD_LOGIC_1164.ALL;
  3. USE IEEE.STD_LOGIC_UNSIGNED.ALL;
  4. ENTITY CLOCK_24 IS
  5. PORT(
  6. CLK : IN STD_LOGIC; -- 时钟输入
  7. RST : IN STD_LOGIC; -- 重置输入
  8. CLK_M : OUT STD_LOGIC_VECTOR(4 DOWNTO 0) -- 当前时间
  9. );
  10. END CLOCK_24;
  11. ARCHITECTURE CLOCK2 OF CLOCK_24 IS
  12. SIGNAL TEM_CLK_M : STD_LOGIC_VECTOR(4 DOWNTO 0) := (OTHERS => '0');
  13. BEGIN
  14. PROCESS(CLK, RST)
  15. BEGIN
  16. IF RST = '0' THEN
  17. TEM_CLK_M <= (OTHERS => '0');
  18. ELSIF CLK'EVENT AND CLK = '1' THEN
  19. IF TEM_CLK_M = "11000" THEN
  20. TEM_CLK_M <= (OTHERS => '0');
  21. ELSE
  22. TEM_CLK_M <= TEM_CLK_M + 1;
  23. END IF;
  24. END IF;
  25. END PROCESS;
  26. CLK_M <= TEM_CLK_M;
  27. END CLOCK2;

6、CLOCK_60:

  1. LIBRARY IEEE;
  2. USE IEEE.STD_LOGIC_1164.ALL;
  3. USE IEEE.STD_LOGIC_UNSIGNED.ALL;
  4. ENTITY CLOCK_60 IS
  5. PORT(
  6. CLK : IN STD_LOGIC; -- 时钟输入
  7. RST : IN STD_LOGIC; -- 重置输入
  8. QOUT : OUT STD_LOGIC; -- 进位输出信号
  9. CLK_M : OUT STD_LOGIC_VECTOR(5 DOWNTO 0) -- 当前时间
  10. );
  11. END CLOCK_60;
  12. ARCHITECTURE CLOCK1 OF CLOCK_60 IS
  13. SIGNAL TEM_CLK_M : STD_LOGIC_VECTOR(5 DOWNTO 0) := (OTHERS => '0');
  14. BEGIN
  15. PROCESS(CLK, RST)
  16. BEGIN
  17. IF RST = '0' THEN
  18. TEM_CLK_M <= (OTHERS => '0');
  19. QOUT <= '0';
  20. ELSIF CLK'EVENT AND CLK = '1' THEN
  21. IF TEM_CLK_M = "111011" THEN
  22. QOUT <= '1';
  23. TEM_CLK_M <= (OTHERS => '0');
  24. ELSE
  25. TEM_CLK_M <= TEM_CLK_M + 1;
  26. QOUT <= '0';
  27. END IF;
  28. END IF;
  29. END PROCESS;
  30. CLK_M <= TEM_CLK_M;
  31. END CLOCK1;

7、clock_display :

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. use ieee.numeric_std.all;
  4. entity clock_display is
  5. Port (
  6. seconds : in std_logic_vector(5 downto 0); -- 输入的秒数(0-59
  7. seg_ten : out std_logic_vector(6 downto 0); -- 十位数码管段
  8. seg_one : out std_logic_vector(6 downto 0)); -- 个位数码管段
  9. end clock_display;
  10. architecture Behavioral of clock_display is
  11. -- 七段数码管译码函数
  12. function seven_seg_decode(num : integer range 0 to 9) return std_logic_vector is
  13. variable seg : std_logic_vector(6 downto 0);
  14. begin
  15. case num is
  16. when 0 => seg := "1000000"; -- A到G(DP省略)
  17. when 1 => seg := "1111001";
  18. when 2 => seg := "0100100";
  19. when 3 => seg := "0110000";
  20. when 4 => seg := "0011001";
  21. when 5 => seg := "0010010";
  22. when 6 => seg := "0000010";
  23. when 7 => seg := "1111000";
  24. when 8 => seg := "0000000";
  25. when 9 => seg := "0010000";
  26. when others => seg := "1111111"; -- 错误指示
  27. end case;
  28. return seg;
  29. end function;
  30. -- 声明变量来存储十位和个位的值
  31. signal ten_val, one_val : integer range 0 to 9;
  32. begin
  33. process(seconds)
  34. begin
  35. -- 计算十位
  36. ten_val <= to_integer(unsigned(seconds)) / 10;
  37. -- 调用译码函数并更新输出
  38. seg_ten <= seven_seg_decode(ten_val);
  39. end process;
  40. process(seconds)
  41. begin
  42. -- 计算个位
  43. one_val <= to_integer(unsigned(seconds)) mod 10;
  44. -- 调用译码函数并更新输出
  45. seg_one <= seven_seg_decode(one_val);
  46. end process;
  47. end Behavioral;

8、TUBE:

  1. LIBRARY IEEE;
  2. USE IEEE.STD_LOGIC_1164.ALL;
  3. USE IEEE.STD_LOGIC_UNSIGNED.ALL;
  4. ENTITY TUBE IS
  5. PORT (
  6. CLK : IN STD_LOGIC;
  7. TUBE_SIX : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
  8. TUBE_FIVE : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
  9. TUBE_FOUR : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
  10. TUBE_THREE : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
  11. TUBE_TWO : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
  12. TUBE_ONE : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
  13. TUBE_NOW : OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
  14. TIME_CLOCK : OUT STD_LOGIC;
  15. EN : OUT STD_LOGIC_VECTOR(5 DOWNTO 0)
  16. );
  17. END TUBE;
  18. ARCHITECTURE ONE OF TUBE IS
  19. SIGNAL TEM_EN : STD_LOGIC_VECTOR(5 DOWNTO 0) := "011111";
  20. SIGNAL TEM_TIME_CLOCK : STD_LOGIC := '1';
  21. SIGNAL FLAG : STD_LOGIC := '0';
  22. SIGNAL TEM_TUBE_SIX : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";
  23. SIGNAL TEM_TUBE_FIVE : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";
  24. SIGNAL TEM_TUBE_FOUR : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";
  25. SIGNAL TEM_TUBE_THREE : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";
  26. SIGNAL TEM_TUBE_TWO : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";
  27. SIGNAL TEM_TUBE_ONE : STD_LOGIC_VECTOR(6 DOWNTO 0) := "0000000";
  28. BEGIN
  29. P1: PROCESS(CLK)
  30. BEGIN
  31. IF CLK'EVENT AND CLK = '1' THEN
  32. TEM_EN <= TEM_EN(4 DOWNTO 0) & TEM_EN(5);
  33. EN <= TEM_EN;
  34. END IF;
  35. END PROCESS P1;
  36. P2: PROCESS(TEM_EN, TUBE_ONE, TUBE_TWO, TUBE_THREE, TUBE_FOUR, TUBE_FIVE, TUBE_SIX)
  37. BEGIN
  38. CASE TEM_EN IS
  39. WHEN "111101" => TUBE_NOW <= TUBE_ONE;
  40. WHEN "111011" => TUBE_NOW <= TUBE_TWO;
  41. WHEN "110111" => TUBE_NOW <= TUBE_THREE;
  42. WHEN "101111" => TUBE_NOW <= TUBE_FOUR;
  43. WHEN "011111" => TUBE_NOW <= TUBE_FIVE;
  44. WHEN "111110" => TUBE_NOW <= TUBE_SIX;
  45. WHEN OTHERS => TUBE_NOW <= (OTHERS => '0');
  46. END CASE;
  47. END PROCESS P2;
  48. P3: PROCESS(CLK)
  49. VARIABLE COUNTER : INTEGER RANGE 0 TO 1000;
  50. BEGIN
  51. TEM_TUBE_SIX <= TUBE_SIX;
  52. TEM_TUBE_FIVE <= TUBE_FIVE;
  53. TEM_TUBE_FOUR <= TUBE_FOUR;
  54. TEM_TUBE_THREE <= TUBE_THREE;
  55. TEM_TUBE_TWO <= TUBE_TWO;
  56. TEM_TUBE_ONE <= TUBE_ONE;
  57. IF (
  58. 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"
  59. ) THEN
  60. COUNTER := 0;
  61. TEM_TIME_CLOCK <= '0';
  62. FLAG <= '1';
  63. ELSIF (
  64. 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"
  65. ) THEN
  66. COUNTER := 0;
  67. TEM_TIME_CLOCK <= '0';
  68. FLAG <= '1';
  69. ELSIF FLAG = '1' THEN
  70. IF CLK'EVENT AND CLK = '1' THEN
  71. COUNTER := COUNTER + 1;
  72. END IF;
  73. IF COUNTER = 1000 THEN
  74. TEM_TIME_CLOCK <= '1';
  75. FLAG <= '0';
  76. END IF;
  77. END IF;
  78. END PROCESS P3;
  79. TIME_CLOCK <= TEM_TIME_CLOCK;
  80. END ONE;

9、原理图连接:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/1016433
推荐阅读
相关标签
  

闽ICP备14008679号