基于VHDL的数字钟设计

这个是以前的一个作业,当时写的比较用心(感觉胸前的红领巾更鲜艳了)。先贴个程序有时间就再写写详细的设计思路吧!(哼,不信你还会继续写。。。)

工程结构如下:
基于VHDL的数字钟设计_第1张图片

下面分部贴上程序

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;	

你可能感兴趣的:(Others)