这个是以前的一个作业,当时写的比较用心(感觉胸前的红领巾更鲜艳了)。先贴个程序有时间就再写写详细的设计思路吧!(哼,不信你还会继续写。。。)
工程结构如下:
下面分部贴上程序
1. 模块综合
-----------------------------------------------------
-- 数字钟
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CLOCK IS
PORT( CLK : IN STD_LOGIC; -- 1Hz时钟信号输入
C_SCALE_SEL : IN STD_LOGIC; -- 时钟进制选择
C_RESET : IN STD_LOGIC; -- 时钟复位信号
C_SET_MIN, C_SET_HOUR : IN STD_LOGIC; -- 时间调节
BUZZER : OUT STD_LOGIC; -- 蜂鸣器控制
SEGMENT_SEL : OUT STD_LOGIC_VECTOR(5 DOWNTO 0); -- 数码位选信号输出
SEGMENT_SEG : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- 数码管段选信号输出
FLASH_LED : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); -- 流水灯
END CLOCK;
ARCHITECTURE BHV OF CLOCK IS
-- 调用秒钟计数模块声明
COMPONENT SECOND_BCD_COUNT
PORT(clk_to_second, reset, set_min : IN STD_LOGIC;
CO : OUT STD_LOGIC;
DATOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END COMPONENT;
-- 调用分钟计数模块声明
COMPONENT MINUTE_BCD_COUNT
PORT(clk_to_minute, reset, set_hour : IN STD_LOGIC;
CO : OUT STD_LOGIC;
DATOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END COMPONENT;
-- 调用小时计数模块声明
COMPONENT HOUR_BCD_COUNT
PORT(clk_to_hour, reset, SCALE_SEL : IN STD_LOGIC;
DATOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END COMPONENT;
-- 调用译码显示模块声明
COMPONENT SELTIME
PORT( SCAN_CLK : IN STD_LOGIC; -- 扫描时钟输入
HOUR, MINUTE, SECOND : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 时间数据输入
SEL : OUT STD_LOGIC_VECTOR(5 DOWNTO 0); -- 位选信号输出
SEG : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); -- 段选信号输出
END COMPONENT;
-- 调用分频模块声明
COMPONENT DEV
PORT( CLK_50MHz : IN STD_LOGIC;
CLK_1Hz, CLK_5Hz, CLK_250Hz : OUT STD_LOGIC);
END COMPONENT;
-- 整点报时模块
COMPONENT ALERT
PORT( CLK : IN STD_LOGIC; -- 激励LED变化
M_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 输入分钟显示数据
S_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 输入秒钟显示数据
SPEAKER : OUT STD_LOGIC; -- 蜂鸣器控制
LED : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); -- 流水灯
END COMPONENT;
-- 按键延时消抖模块
COMPONENT KEY_DELAY
PORT(CLK, KEY_IN : IN STD_LOGIC;
KEY_OUT : OUT STD_LOGIC);
END COMPONENT;
SIGNAL AD_HOUR, AD_MIN : STD_LOGIC; -- 时钟调节信号
SIGNAL S_CO, M_CO : STD_LOGIC; -- 计数进位
SIGNAL C_CLK, SCAN_CLK, FLOW_CLK : STD_LOGIC; -- 计数时钟,扫描时钟,流水灯驱动时钟
SIGNAL S_DAT, M_DAT, H_DAT : STD_LOGIC_VECTOR(7 DOWNTO 0); -- 秒,分,时显示数据
BEGIN
u1 : SECOND_BCD_COUNT PORT MAP(C_CLK, C_RESET, AD_MIN, S_CO, S_DAT); -- 秒钟
u2 : MINUTE_BCD_COUNT PORT MAP(S_CO, C_RESET, AD_HOUR, M_CO, M_DAT); -- 分钟
u3 : HOUR_BCD_COUNT PORT MAP(M_CO, C_RESET, C_SCALE_SEL, H_DAT); -- 小时
u4 : SELTIME PORT MAP(SCAN_CLK, H_DAT, M_DAT, S_DAT, SEGMENT_SEL, SEGMENT_SEG); -- 译码显示
u5 : DEV PORT MAP(CLK, C_CLK, FLOW_CLK , SCAN_CLK); -- 分频
u6 : KEY_DELAY PORT MAP(SCAN_CLK, C_SET_MIN, AD_MIN); -- 分钟调整
u7 : KEY_DELAY PORT MAP(SCAN_CLK, C_SET_HOUR, AD_HOUR); -- 小时调整
u8 : ALERT PORT MAP(FLOW_CLK, M_DAT,S_DAT, BUZZER, FLASH_LED); -- 整点报时
END BHV;
2. 时分秒计数模块
-----------------------------------------------------
-- 小时24进制或12进制的BCD计数模块
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY HOUR_BCD_COUNT IS
PORT(clk_to_hour, reset, SCALE_SEL : IN STD_LOGIC;
DATOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END HOUR_BCD_COUNT;
ARCHITECTURE BHV OF HOUR_BCD_COUNT IS
SIGNAL COUNT_SHI, COUNT_GE : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
PROCESS(clk_to_hour, reset) BEGIN
IF reset = '0' THEN COUNT_SHI <= "0000"; COUNT_GE <= "0000"; -- 有复位信号,则清除计数。
ELSIF clk_to_hour'EVENT AND clk_to_hour = '1' THEN
IF SCALE_SEL = '1' THEN -- 24进制
IF COUNT_SHI = "0010" AND COUNT_GE = "0011" THEN COUNT_SHI <= "0000"; COUNT_GE <= "0000"; -- 24进制溢出清零
ELSIF COUNT_GE < "1001" THEN COUNT_GE <= COUNT_GE + 1;
ELSE COUNT_GE <= "0000"; COUNT_SHI <= COUNT_SHI + 1;
END IF;
ELSE -- 12进制
IF COUNT_SHI = "0001" AND COUNT_GE = "0001" THEN COUNT_SHI <= "0000"; COUNT_GE <= "0000"; -- 12进制溢出清零
ELSIF COUNT_GE < "1001" THEN COUNT_GE <= COUNT_GE + 1;
ELSE COUNT_GE <= "0000"; COUNT_SHI <= COUNT_SHI + 1;
END IF;
END IF;
END IF;
DATOUT <= COUNT_SHI & COUNT_GE; -- 数据输出
END PROCESS;
END BHV;
-----------------------------------------------------
-- 分钟BCD60进制计数
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY MINUTE_BCD_COUNT IS
PORT(clk_to_minute, reset, set_hour : IN STD_LOGIC;
CO : OUT STD_LOGIC;
DATOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END MINUTE_BCD_COUNT;
ARCHITECTURE BHV OF MINUTE_BCD_COUNT IS
SIGNAL COUNT_SHI, COUNT_GE : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL COUNT_EN : STD_LOGIC;
BEGIN
CO <= set_hour OR COUNT_EN;
PROCESS(clk_to_minute, set_hour, reset) BEGIN
IF reset = '0' THEN COUNT_SHI <= "0000"; COUNT_GE <= "0000"; -- 有复位信号,则清除计数
ELSIF clk_to_minute'EVENT AND clk_to_minute = '1' THEN
IF COUNT_SHI = "0101" AND COUNT_GE = "1001" THEN
COUNT_SHI <= "0000"; COUNT_GE <= "0000"; COUNT_EN <= '1'; -- 计数进位(信号量不是立即赋值,需等下一个时钟信号到来。)
ELSIF COUNT_GE < "1001" THEN COUNT_GE <= COUNT_GE + 1; COUNT_EN <= '0';
ELSE COUNT_GE <= "0000"; -- 计数溢出则清零,并产生进位
IF COUNT_SHI < "1010" THEN COUNT_SHI <= COUNT_SHI + 1;
ELSE COUNT_SHI <= "0000";
END IF;
END IF;
END IF;
END PROCESS;
DATOUT <= COUNT_SHI & COUNT_GE; -- 数据输出
END BHV;
-----------------------------------------------------
-- 秒钟BCD60进制计数
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY SECOND_BCD_COUNT IS
PORT(clk_to_second, reset, set_min : IN STD_LOGIC;
CO : OUT STD_LOGIC;
DATOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END SECOND_BCD_COUNT;
ARCHITECTURE BHV OF SECOND_BCD_COUNT IS
SIGNAL COUNT_SHI, COUNT_GE : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL COUNT_EN : STD_LOGIC;
BEGIN
CO <= set_min OR COUNT_EN;
PROCESS(clk_to_second, reset, set_min) BEGIN
IF reset = '0' THEN COUNT_SHI <= "0000"; COUNT_GE <= "0000"; -- 有复位信号,则清除计数
ELSIF clk_to_second'EVENT AND clk_to_second = '1' THEN
IF COUNT_SHI = "0101" AND COUNT_GE = "1001" THEN
COUNT_SHI <= "0000"; COUNT_GE <= "0000"; COUNT_EN <= '1'; -- 计数进位(信号量不是立即赋值,需等下一个时钟信号到来。)
ELSIF COUNT_GE < "1001" THEN COUNT_GE <= COUNT_GE + 1; COUNT_EN <= '0';
ELSE COUNT_GE <= "0000";
IF COUNT_SHI < "1010" THEN COUNT_SHI <= COUNT_SHI + 1;
ELSE COUNT_SHI <= "0000";
END IF;
END IF;
END IF;
DATOUT <= COUNT_SHI & COUNT_GE; -- 数据输出
END PROCESS;
END BHV;
3. 数码管译码显示模块
-----------------------------------------------------
-- 数码管译码显示模块
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY SELTIME IS
PORT( SCAN_CLK : IN STD_LOGIC; -- 扫描时钟输入
HOUR, MINUTE, SECOND : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 时间数据输入
SEL : OUT STD_LOGIC_VECTOR(5 DOWNTO 0); -- 位选信号输出
SEG : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); -- 段选信号输出
END SELTIME;
ARCHITECTURE BHV OF SELTIME IS
SIGNAL SCAN_COUNT : STD_LOGIC_VECTOR(2 DOWNTO 0); -- 扫描计数
SIGNAL DAT : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
-- 位选扫描进程
SCAN : PROCESS(SCAN_CLK) BEGIN
IF SCAN_CLK'EVENT AND SCAN_CLK = '1' THEN
IF(SCAN_COUNT > "101") THEN SCAN_COUNT <= "000";
ELSE SCAN_COUNT <= SCAN_COUNT + 1;
END IF;
END IF;
CASE SCAN_COUNT IS
WHEN "000" => DAT <= SECOND(3 DOWNTO 0);
WHEN "001" => DAT <= SECOND(7 DOWNTO 4);
WHEN "010" => DAT <= MINUTE(3 DOWNTO 0);
WHEN "011" => DAT <= MINUTE(7 DOWNTO 4);
WHEN "100" => DAT <= HOUR(3 DOWNTO 0);
WHEN "101" => DAT <= HOUR(7 DOWNTO 4);
WHEN OTHERS => NULL;
END CASE;
END PROCESS SCAN;
-- 译码显示进程 共数码管编码
DECODE : PROCESS(SCAN_COUNT) BEGIN
CASE DAT IS
WHEN "0000" => SEG<="11000000";
WHEN "0001" => SEG<="11111001";
WHEN "0010" => SEG<="10100100";
WHEN "0011" => SEG<="10110000";
WHEN "0100" => SEG<="10011001";
WHEN "0101" => SEG<="10010010";
WHEN "0110" => SEG<="10000010";
WHEN "0111" => SEG<="11111000";
WHEN "1000" => SEG<="10000000";
WHEN "1001" => SEG<="10010000";
WHEN OTHERS => SEG<="11111111";
END CASE;
END PROCESS DECODE;
-- 3-8译码
SEL <= "111110" WHEN SCAN_COUNT = "000" ELSE
"111101" WHEN SCAN_COUNT = "001" ELSE
"111011" WHEN SCAN_COUNT = "010" ELSE
"110111" WHEN SCAN_COUNT = "011" ELSE
"101111" WHEN SCAN_COUNT = "100" ELSE
"011111" WHEN SCAN_COUNT = "101" ELSE
"111111";
END BHV;
4. 分频模块,晶振频率50MHz
-----------------------------------------------------
-- 分频模块
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DEV IS
PORT( CLK_50MHz : IN STD_LOGIC;
CLK_1Hz, CLK_5Hz, CLK_250Hz : OUT STD_LOGIC);
END;
ARCHITECTURE BHV OF DEV IS
SIGNAL Q1 : INTEGER RANGE 0 TO 49999999;
SIGNAL Q2 : INTEGER RANGE 0 TO 199999;
SIGNAL Q3 : INTEGER RANGE 0 TO 9999999;
BEGIN
PROCESS(CLK_50MHz) BEGIN
IF CLK_50MHz'EVENT AND CLK_50MHz = '1' THEN
-- 1Hz
IF Q1 < 25000000 THEN CLK_1Hz <= '0'; Q1 <= Q1 + 1;
ELSIF Q1 < 49999999 THEN CLK_1Hz <= '1'; Q1 <= Q1 + 1;
ELSE Q1 <= 0;
END IF;
-- 250Hz
IF Q2 < 100000 THEN CLK_250Hz <= '0'; Q2 <= Q2 + 1;
ELSIF Q2 < 199999 THEN CLK_250Hz <= '1'; Q2 <= Q2 + 1;
ELSE Q2 <= 0;
END IF;
-- 5Hz
IF Q3 < 5000000 THEN CLK_5Hz <= '0'; Q3 <= Q3 + 1;
ELSIF Q3 < 9999999 THEN CLK_5Hz <= '1'; Q3 <= Q3 + 1;
ELSE Q3 <= 0;
END IF;
END IF;
END PROCESS;
END;
5. 按键延时消抖模块(PS:这个很重要,网上借鉴的。。。_)
-----------------------------------------------------
-- 按键延时消抖模块
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY KEY_DELAY IS
PORT(CLK, KEY_IN : IN STD_LOGIC;
KEY_OUT : OUT STD_LOGIC);
END KEY_DELAY;
ARCHITECTURE BHV OF KEY_DELAY IS
BEGIN
PROCESS(CLK, KEY_IN)
VARIABLE COUNT : INTEGER RANGE 0 TO 10;
BEGIN
IF CLK'EVENT AND CLK = '1' THEN
IF KEY_IN = '0' THEN
IF COUNT < 10 THEN COUNT := COUNT + 1;
ELSE COUNT := COUNT; -- 赋予变量的值是即刻生效的,在此后的代码中,此变量将使用新的变量值。
END IF;
IF COUNT = 9 THEN KEY_OUT <= '1';
ELSE KEY_OUT <= '0';
END IF;
ELSE COUNT := 0;
END IF;
END IF;
END PROCESS;
END BHV;
6. 报时模块
-----------------------------------------------------
-- 报时模块,就是整点时发生点变化喽,这个你随意。Hi,guys.
-----------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY ALERT IS
PORT( CLK : IN STD_LOGIC; -- 激励LED变化
M_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 输入分钟显示数据
S_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 输入秒钟显示数据
SPEAKER : OUT STD_LOGIC; -- 蜂鸣器控制
LED : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); -- 流水灯
END ALERT;
ARCHITECTURE BHV OF ALERT IS
SIGNAL SEL : STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL COUNT : STD_LOGIC_VECTOR(2 DOWNTO 0);
BEGIN
REG : PROCESS(CLK) BEGIN
IF CLK'EVENT AND CLK = '1' THEN
IF COUNT < "111" THEN COUNT <= COUNT + 1;
ELSE COUNT <= "000";
END IF;
END IF;
END PROCESS REG;
FLOW : PROCESS(COUNT, M_IN, S_IN) BEGIN
IF M_IN = "00000000" AND S_IN < "00001001" THEN -- 整点闪烁
CASE COUNT IS
WHEN "000" => LED <="1000";
WHEN "001" => LED <="0100";
WHEN "010" => LED <="0010";
WHEN "011" => LED <="0001";
WHEN "111" => LED <="1111";
WHEN "101" => LED <="0000";
WHEN "110" => LED <="1111";
WHEN OTHERS => LED <="0000";
END CASE;
ELSE LED <= "0000";
END IF;
END PROCESS FLOW;
BEEP : PROCESS( M_IN, S_IN) BEGIN
IF M_IN = "00000000" AND S_IN < "0000010" THEN -- 整点报时
SPEAKER <= '0';
ELSE SPEAKER <= '1';
END IF;
END PROCESS BEEP;
END BHV;