FPGA数字钟设计

一、使用说明与整体思路概述

1、使用说明:
本设计模拟手机时钟实现四个功能,分别为时间显示、秒表、闹钟、计时器。以BUT1~BUT4分别选择这四个功能,四个功能互不冲突,在时间显示时可以继续进行秒表和计时器的工作。实现的各自功能如下:
时间显示:以1HZ频率显示时间,按下BUT5实现设置时间,在设置时间的条件下,按下BUT6实现对哪个位进行修改操作,设置的位闪烁示意正在设置该位,按BUT6可以将位循环左移。在按下BUT6的情况下,按BUT7实现加一操作,按BUT8实现减一操作。秒个位设置范围为09,秒十位设置范围为05,分钟与小时以此类推。设置完数字后按BUT5完成设置。另外,在时间显示界面增加两个涉及秒表的功能键,在没有设置时间时,按下BUT8可以选择是否开启闹钟,开启闹钟时LED8亮,没有开启闹钟时LED8灭。当闹钟时间到时,LED1亮,按下BUT7可以关闭闹钟。
秒表:以100HZ频率显示百分秒,按下BUT5开始,再按一次BUT5实现暂停。按下BUT6实现计数清零(要再次开始计数必须再按一次BUT6取消清零),按下BUT7标记此时的数字,按BUT8可以显示上次标记的数字,在查看标记的数字后,再按一次BUT8可以返回秒表界面显示,在标记数字,查看标记数字的过程中,秒表一直在计数,不会中断。
闹钟:按下BUT6实现对哪个位进行修改操作,设置的位闪烁示意正在设置该位,按BUT6可以将位循环左移。在按下BUT6的情况下,按BUT7实现加一操作,按BUT8实现减一操作。设置完数字之后,按下BUT5确定完成设置,否则不会闹钟生效。闹钟生效的前提是LED8亮。
计时器:按下BUT6实现对哪个位进行修改操作,设置的位闪烁示意正在设置该位,按BUT6可以将位循环左移。在按下BUT6的情况下,按BUT7实现加一操作,按BUT8实现减一操作。秒个位设置范围为0-9,秒十位设置范围为0~5,分钟与小时以此类推。设置完数字后按BUT5完成设置。完成设置后开始倒计时,倒计时到0时LED4亮,模拟手机计时器时间到后响铃,按下BUT5关闭,即LED4灭。
2、整体思路概述
首先明确四个功能都需要用到数码管,所以用一个变量en来区分四个功能,en设置为两位的变量即可。由于BUT1-BUT4用于随时选择使用什么功能,因此在进入某一个功能之后,BUT1-BUT4最好不要用,因此采用BUT5-BUT8为四个功能下的设置键。在设定时间时BUT6-BUT8可以用于设定时间,在没有设定时时BUT6~BUT8可以用于其他功能。因此可以在时间显示界面控制闹钟。在顶层文件中对en的情况分类进行处理,在顶层文件中接收按键产生的信号,进行处理后得到诸如四种情况下的bcddata,led等等信号,送到其他的模块进行结果的显示。因此设计5个模块,一个模块用于时钟的产生,产生1HZ和100HZ两种信号。一个模块用于按键消抖,一个模块用于检测按键,一个模块用于数码管的显示,一个模块用于LED的显示。

二、程序具体设计

1、时钟模块

----------------------------------------
--时钟模块,产生1s和10ms的时钟
----------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;

entity clock_source IS
PORT(clk:IN  STD_LOGIC;
     clk_1s:out std_LOGIC;
	  clk_10ms: out std_LOGIC;
	  clkcnt: buffer STD_LOGIC_VECTOR(30 DOWNTO 0):= (others =>'0');
     Stopwatch_clear: in std_LOGIC
 );
END clock_source;
ARCHITECTURE behav OF clock_source IS
SIGNAL a: integer range 0 to 24999999 :=0;  --秒
SIGNAL q: STD_LOGIC :='0';          --初始化为0
SIGNAL b: integer range 0 to 249999 :=0;  --百分秒
SIGNAL p: STD_LOGIC :='0';          --初始化为0
begin


process(clk,clkcnt)
begin
  if(rising_edge(clk))then
		clkcnt<= clkcnt + 1;
  end if;
end process;
------------------------------产生 1S 的时钟信号---------------
process(clk)
begin
		if(clk'event and clk='1' ) then
			if a=24999999 then        --25000000个clk脉冲(20ns)即0.5秒为低电平,0.5秒为高电平,即产生周期1秒的方波信号。
				 a<=0;
				 q<= not q;
			else
				 a<=a+1;		
			end if;
		end if;
		clk_1s<=q;
end process;
------------------------------------

------------------------------产生 10MS 的时钟信号---------------
process(clk)
begin
		if(clk'event and clk='1' ) then
			if(Stopwatch_clear='1') then
				b<=0;
				p<='0';
			else
				if b=249999 then        --250000个clk脉冲(20ns)即0.005秒为低电平,0.005秒为高电平,即产生周期0.01秒的方波信号。
				  b<=0;
				  p<= not p;
				else
				  b<=b+1;		
				end if;
			end if;
		 end if;	
		clk_10ms<=p;
end process;
------------------------------------
end architecture behav;

设计原理与分析:FPGA为50MHZ,采用计数分频的方法获得1HZ与100HZ时钟,1HZ与100HZ分别用各自的变量,互不影响,防止秒表和时间显示产生冲突。
值得注意的是,由于数码管显示用到了clkcnt,因此clkcnt设置为buffer,另外,秒表的清零需要将100HZ的信号切断,因此在port中有Stopwatch_clear: in std_LOGIC。
2、按键消抖模块

--按键消抖模块:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity keyfilt is
port (clk  : in  std_logic;
		key1 : in  std_logic;
		key1_filt : out std_logic;
		key2 : in  std_logic;
		key2_filt : out std_logic;
		key3: in  std_logic;
		key3_filt: out std_logic;
		key4 : in  std_logic;
		key4_filt : out std_logic;
		key5 : in  std_logic;
		key5_filt : out std_logic;
		key6 : in  std_logic;
		key6_filt : out std_logic;
		key7: in  std_logic;
		key7_filt: out std_logic;
		key8 : in  std_logic;
		key8_filt : out std_logic
		);
end keyfilt;
architecture behavioral of keyfilt is
signal keycnt1 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
signal keycnt2 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
signal keycnt3 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
signal keycnt4 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
signal keycnt5 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
signal keycnt6 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
signal keycnt7 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
signal keycnt8 : integer range 0 to 50000000:=0;--通用cnt,因为正常情况下不可能有两个按键同时按下
constant N :integer := 5000000;	--消抖时间,对于50Mhz的基准时钟,这相当于0.1S,一般要在20ms以上
begin
	process (clk)
	begin 
		if clk'event and clk = '1' then
			if key1 = '0' then 	--当keyX输入低电平,即按键按下
				if keycnt1 /= N then --一直计数到N,  /=  为不等于
					keycnt1<= keycnt1 + 1;
				end if;
				if keycnt1 = N-1 then --最后一个计数时输出keyX_filt脉冲
					key1_filt<= '1';
				else
					key1_filt<= '0';
				end if;
			else 					--若keyX输入高电平,表明按键被释放
				keycnt1<= 0;
			end if;
		
		

			if key2 = '0' then 	
				if keycnt2 /= N then 
					keycnt2<= keycnt2 + 1;
				end if;
				if keycnt2 = N-1 then 
					key2_filt<= '1';
				else
					key2_filt<= '0';
				end if;
			else 					
				keycnt2<= 0;
			end if;

			
			if key3 = '0' then 	
				if keycnt3 /= N then 
					keycnt3<= keycnt3 + 1;
				end if;
				if keycnt3 = N-1 then 
					key3_filt<= '1';
				else
					key3_filt<= '0';
				end if;
			else 					
				keycnt3<= 0;
			end if;



			if key4 = '0' then 	
				if keycnt4 /= N then 
					keycnt4<= keycnt4 + 1;
				end if;
				if keycnt4 = N-1 then 
					key4_filt<= '1';
				else
					key4_filt<= '0';
				end if;
			else 					
				keycnt4<= 0;
			end if;


			if key5 = '0' then 	
				if keycnt5 /= N then 
					keycnt5<= keycnt5 + 1;
				end if;
				if keycnt5 = N-1 then 
					key5_filt<= '1';
				else
					key5_filt<= '0';
				end if;
			else 					
				keycnt5<= 0;
			end if;
	

			if key6 = '0' then 	
				if keycnt6 /= N then 
					keycnt6<= keycnt6 + 1;
				end if;
				if keycnt6 = N-1 then 
					key6_filt<= '1';
				else
					key6_filt<= '0';
				end if;
			else 					
				keycnt6<= 0;
			end if;

		
			if key7 = '0' then 	
				if keycnt7 /= N then 
					keycnt7<= keycnt7 + 1;
				end if;
				if keycnt7 = N-1 then 
					key7_filt<= '1';
				else
					key7_filt<= '0';
				end if;
			else 					
				keycnt7<= 0;
			end if;
		

	
			if key8 = '0' then 	
				if keycnt8 /= N then 
					keycnt8<= keycnt8 + 1;
				end if;
				if keycnt8 = N-1 then 
					key8_filt<= '1';
				else
					key8_filt<= '0';
				end if;
			else 					
				keycnt8<= 0;
			end if;
		
		
		end if;	--clk'event
	end process;		
		
end behavioral;

设计原理与分析:例化时keyX对应实际的按键,key_filt为keyX按下时产生的对应的脉冲。实际上是采用延时的方法对按键进行消抖。八个按键分别用不同的信号进行操作,避免相互影响。
3、按键检测模块

----------------------------------------
--按键状态检测模块
----------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;

entity key_state IS
PORT(clk:IN  STD_LOGIC;
     key1_filt:in std_LOGIC;
	  key2_filt:in std_LOGIC;
	  key3_filt:in std_LOGIC;
	  key4_filt:in std_LOGIC;
	  key5_filt:in std_LOGIC;
	  key6_filt:in std_LOGIC;
	  key7_filt:in std_LOGIC;
	  key8_filt:in std_LOGIC;
	  en: buffer std_logic_vector(1 downto 0);
	  skey5: buffer std_LOGIC;
	  alarm_key5: buffer std_LOGIC;
	  count_down_clock_skey5: buffer std_LOGIC;
	  skey6: out std_LOGIC;
	  skey7: out std_LOGIC;
	  skey8: buffer std_LOGIC
 );
END key_state;
ARCHITECTURE behav OF key_state IS
begin
process(clk)
begin
  if(clk'event and clk='1' )then
     if(key1_filt='1') then
	      en<="00";--时间显示
	  end if;
     if(key2_filt='1') then
	      en<="01";--秒表
	  end if;
     if(key3_filt='1') then
	      en<="10";--闹钟
	  end if;
     if(key4_filt='1') then
	      en<="11";--定时器
	  end if;	  
     if(key5_filt='1') then
			if(en="00") then--闹钟清除也用到了key5_filt,为了避免对设置时间的影响,加en=00的限制条件
				skey5<=not skey5;--设置时间用到反转
			end if;
			if(en="10") then
				alarm_key5<=not alarm_key5;
			end if;
			if(en="11") then 
				count_down_clock_skey5<=not count_down_clock_skey5;
			end if;
	  end if;	
     if(key6_filt='1') then
	      skey6<='1';
	  end if;	
     if(key7_filt='1') then
	      skey7<='1';
	  end if;	
     if(key8_filt='1') then
	      skey8<=not skey8;--秒表用到反转
	  end if;	
  end if;
end process;
end architecture behav;

设计原理与分析:对按键消抖后的脉冲进行检测,如果检测到就证明有对应的按键按下,则可以进行对控制变量的翻转或者是跟随脉冲一起变化,形成脉冲控制信号和电平信号两种控制信号,比如说,在时间显示功能时,设否设置时间可以用电平控制信号,而加减1则用脉冲控制信号。key1_filt-key4_filt检测到脉冲时,改变en的值。对于key5_filt~key8_filt有的需要在该条件下判断处于什么功能,进而改变相应的信号。
4、数码管显示模块

----------------------------------------
--数码管显示模块
----------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;

entity seg_display IS
PORT(clk:IN  STD_LOGIC;
	  clk_1s: in std_LOGIC;
	  clkcnt: in STD_LOGIC_VECTOR(30 DOWNTO 0);
	  en:in std_logic_vector(1 downto 0);
	  bcddata: in std_logic_vector(23 downto 0);
	  set_time: in std_LOGIC;
	  bcddata_temp:in std_logic_vector(23 downto 0);
	  position: in integer range 0 to 20;
	  Stopwatch_show_savedata:in std_LOGIC:='0';
	  Stopwatch_save_data:in std_logic_vector(23 downto 0);
	  bcddata_Stopwatch:in std_logic_vector(23 downto 0);
	  bcddata_alarm:in std_logic_vector(23 downto 0);
	  alarm_select:in std_LOGIC:='0';
	  bcddata_count_down_clock:in std_logic_vector(23 downto 0);
	  count_down_clock_select:in std_LOGIC;
	  segdot:OUT STD_LOGIC;
	  SEG_LED:OUT STD_LOGIC_VECTOR(6 downto 0);
     SEG_NCS:OUT STD_LOGIC_VECTOR(5 downto 0)
 );
END seg_display;
ARCHITECTURE behav OF seg_display IS
SIGNAL bcd_led:STD_LOGIC_VECTOR(3 DOWNTO 0):=(others=>'0'); 
begin
process(clkcnt(17 downto 15))
 begin
   case clkcnt(17 downto 15) is
      when "000" =>	
						  if(en="00") then
								if(set_time='1') then
									bcd_led<=bcddata_temp(3  downto 0);
									if(position=0)  then
										if(clk_1s='1') then
											SEG_NCS <= "111110";
										else
											SEG_NCS <= "111111";
										end if;
									else
										SEG_NCS <= "111110";
									end if;
								else
									bcd_led<=bcddata(3  downto 0);
									SEG_NCS <= "111110";
								end if;
							end if;
							if(en="01") then 
								if(Stopwatch_show_savedata='1') then 
									bcd_led<=Stopwatch_save_data(3 downto 0);
								else
									bcd_led<=bcddata_Stopwatch(3 downto 0);
								end if;
								SEG_NCS <= "111110";
							end if;
						  if(en="10") then
								bcd_led<=bcddata_alarm(3  downto 0);
								if(position=0)  then
									if(clk_1s='1') then
										SEG_NCS <= "111110";
									else
										if(alarm_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "111110";
								end if;
							end if;
						  if(en="11") then
								bcd_led<=bcddata_count_down_clock(3  downto 0);
								if(position=0)  then
									if(clk_1s='1') then
										SEG_NCS <= "111110";
									else
										if(count_down_clock_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "111110";
								end if;
							end if;							
							segdot<='1';
      when "001" =>								
						  if(en="00") then
								if(set_time='1') then
									bcd_led<=bcddata_temp(7  downto 4);
									if(position=4)  then
										if(clk_1s='1') then
											SEG_NCS <= "111101";
										else
											SEG_NCS <= "111111";
										end if;
									else
										SEG_NCS <= "111101";									
									end if;
							    else
									bcd_led<=bcddata(7  downto 4);
									SEG_NCS <= "111101";
								 end if;
							end if;
							if(en="01") then 
								if(Stopwatch_show_savedata='1') then 
									bcd_led<=Stopwatch_save_data(7 downto 4);
								else
									bcd_led<=bcddata_Stopwatch(7 downto 4);
								end if;
								SEG_NCS <= "111101";
							end if;
						  if(en="10") then
								bcd_led<=bcddata_alarm(7  downto 4);
								if(position=4)  then
									if(clk_1s='1') then
										SEG_NCS <= "111101";
									else
										if(alarm_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "111101";
								end if;
							end if;
						  if(en="11") then
								bcd_led<=bcddata_count_down_clock(7  downto 4);
								if(position=4)  then
									if(clk_1s='1') then
										SEG_NCS <= "111101";
									else
										if(count_down_clock_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "111101";
								end if;
							end if;
							segdot<='1';
							
      when "010" =>	
						  if(en="00") then
								if(set_time='1') then
									bcd_led<=bcddata_temp(11  downto 8);
									if(position=8)  then
										if(clk_1s='1') then
											SEG_NCS <= "111011";
										else
											SEG_NCS <= "111111";
										end if;
									else
										SEG_NCS <= "111011";
									end if;
								else
									bcd_led<=bcddata(11  downto 8);
									SEG_NCS <= "111011";
								end if;
							end if;
							if(en="01") then 
								if(Stopwatch_show_savedata='1') then 
									bcd_led<=Stopwatch_save_data(11 downto 8);
								else
									bcd_led<=bcddata_Stopwatch(11 downto 8);
								end if;
								SEG_NCS <= "111011";
							end if;
						  if(en="10") then
								bcd_led<=bcddata_alarm(11  downto 8);
								if(position=8)  then
									if(clk_1s='1') then
										SEG_NCS <= "111011";
									else
										if(alarm_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "111011";
								end if;
							end if;
						  if(en="11") then
								bcd_led<=bcddata_count_down_clock(11  downto 8);
								if(position=8)  then
									if(clk_1s='1') then
										SEG_NCS <= "111011";
									else
										if(count_down_clock_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "111011";
								end if;
							end if;
							segdot<='0';
      when "011" =>	
						  if(en="00") then
								if(set_time='1') then
									bcd_led<=bcddata_temp(15  downto 12);
									if(position=12)  then
										if(clk_1s='1') then
											SEG_NCS <= "110111";
										else
											SEG_NCS <= "111111";
										end if;
									else
										SEG_NCS <= "110111";
										
									end if;
								else
									bcd_led<=bcddata(15  downto 12);
									SEG_NCS <= "110111";
								end if;
							end if;
							if(en="01") then 
								if(Stopwatch_show_savedata='1') then 
									bcd_led<=Stopwatch_save_data(15 downto 12);
								else
									bcd_led<=bcddata_Stopwatch(15 downto 12);
								end if;
								SEG_NCS <= "110111";
							end if;
						  if(en="10") then
								bcd_led<=bcddata_alarm(15  downto 12);
								if(position=12)  then
									if(clk_1s='1') then
										SEG_NCS <= "110111";
									else
										if(alarm_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "110111";
								end if;
							end if;
						  if(en="11") then
								bcd_led<=bcddata_count_down_clock(15  downto 12);
								if(position=12)  then
									if(clk_1s='1') then
										SEG_NCS <= "110111";
									else
										if(count_down_clock_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "110111";
								end if;
							end if;
							segdot<='1';
      when "100" =>	
						  if(en="00") then
								if(set_time='1') then
									bcd_led<=bcddata_temp(19  downto 16);
									if(position=16)  then
										if(clk_1s='1') then
											SEG_NCS <= "101111";
										else
											SEG_NCS <= "111111";
										end if;
									else
										SEG_NCS <= "101111";
									end if;
								else
									bcd_led<=bcddata(19  downto 16);
									SEG_NCS <= "101111";
								end if;
							end if;
							if(en="01") then 
								if(Stopwatch_show_savedata='1') then 
									bcd_led<=Stopwatch_save_data(19 downto 16);
								else
									bcd_led<=bcddata_Stopwatch(19 downto 16);
								end if;
								SEG_NCS <= "101111";
							end if;
						  if(en="10") then
								bcd_led<=bcddata_alarm(19  downto 16);
								if(position=16)  then
									if(clk_1s='1') then
										SEG_NCS <= "101111";
									else
										if(alarm_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "101111";
								end if;
							end if;
						  if(en="11") then
								bcd_led<=bcddata_count_down_clock(19  downto 16);
								if(position=16)  then
									if(clk_1s='1') then
										SEG_NCS <= "101111";
									else
										if(count_down_clock_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "101111";
								end if;
							end if;
							segdot<='0';
      when "101" =>			
						  if(en="00") then
								if(set_time='1') then
									bcd_led<=bcddata_temp(23  downto 20);
									if(position=20)  then
										if(clk_1s='1') then
											SEG_NCS <= "011111";
										else
											SEG_NCS <= "111111";
										end if;
									else
										SEG_NCS <= "011111";
									end if;
								else
									bcd_led<=bcddata(23  downto 20);
									SEG_NCS <= "011111";
								end if;
							end if;
							if(en="01") then 
								if(Stopwatch_show_savedata='1') then 
									bcd_led<=Stopwatch_save_data(23 downto 20);
								else
									bcd_led<=bcddata_Stopwatch(23 downto 20);
								end if;
								SEG_NCS <= "011111";
							end if;
						  if(en="10") then
								bcd_led<=bcddata_alarm(23  downto 20);
								if(position=20)  then
									if(clk_1s='1') then
										SEG_NCS <= "011111";
									else
										if(alarm_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "011111";
								end if;
							end if;
						  if(en="11") then
								bcd_led<=bcddata_count_down_clock(23  downto 20);
								if(position=20)  then
									if(clk_1s='1') then
										SEG_NCS <= "011111";
									else
										if(count_down_clock_select='0') then
											SEG_NCS <= "111111";
										end if;
									end if;
								else
									SEG_NCS <= "011111";
								end if;
							end if;
							segdot<='1';
      when others => SEG_NCS <= "111111";

   end case;
end process;

process(bcd_led)
	begin
			case bcd_led is
										  -- "abcdefg"
				WHEN "0000"=>SEG_LED<="0000001";
				WHEN "0001"=>SEG_LED<="1001111";
				WHEN "0010"=>SEG_LED<="0010010";
				WHEN "0011"=>SEG_LED<="0000110";
				WHEN "0100"=>SEG_LED<="1001100";
				WHEN "0101"=>SEG_LED<="0100100";
				WHEN "0110"=>SEG_LED<="0100000";
				WHEN "0111"=>SEG_LED<="0001111";
				WHEN "1000"=>SEG_LED<="0000000";
				WHEN "1001"=>SEG_LED<="0000100";
				WHEN OTHERS=>SEG_LED<="1111111";
			end case;
end process;
end ARCHITECTURE behav;

设计原理与分析:对于数码管采用分时显示的方法,通过检测clkcnt的17~15位,分别在不同的组合情况下进行单个数码管的显示。在对应的数码管要显示时,判断en的值,根据en的值将不同的bcddata复制给bcd_led,在时间显示时用bcddata,在秒表时用bcddata_Stopwatch,在闹钟时用bcddata_alarm,在计时器时用bcddata_count_down_clock。对与数码管的片选信号SEG_NCS则在需不需要闪烁时判断复制,通过clk_1s的信号达到闪烁的效果 。
5、LED控制模块

--按键消抖模块:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity led_contro is
port (clk  : in  std_logic;
	   alarm_clear: in std_logic;
		led_alarm_not_exit: out std_logic;
		count_down_clock_select: in std_logic;
		bcddata_count_down_clock:in std_logic_vector(23 downto 0);
		led_count_down_clock:out std_logic
		);
end led_contro;
architecture behav of led_contro is

begin
--闹钟的灯
process(clk)
begin
	if(alarm_clear='1') then 
		led_alarm_not_exit<='1';
	else
		led_alarm_not_exit<='0';
	end if;
end process;

--定时器的灯
process(clk)
begin	
	if(count_down_clock_select='1') then
		if(bcddata_count_down_clock=0) then 
			led_count_down_clock<='0';
		end if;
	else
		led_count_down_clock<='1';
	end if;
end process;
end architecture behav;

设计原理与分析:在LED的控制中,只有闹钟和定时器会用到。因此在PORT中只有闹钟和定时器的信号传进这个模块。
6、顶层文件

----------------------------------------------------------------------------------
--function :
--en=00:时间显示,按5设置时间,6移位,7加,8减,设置完后按5完成设置;在没有设置时间时,按8打开闹钟,指示灯LED8亮,再按一次关闭闹钟,LED8灭
--en=01:秒表,按5开始计时,按6清零,再按6取消清零,按5可以暂停,按7标记此时的时间,按8显示标记的时间,再按8返回秒表计时显示
--en=10:闹钟时间设置,按5设置时间,再按一次完成设置(没有完成设置,及时LED8亮也没有用),6移位,7加,8减,闹钟时间到时LED1亮,按7可以灭灯,只是灭灯,不会关闭闹钟
--en=11:定时器显示,按5设置时间,再按一次完成设置,6移位,7加,8减,计时到0时LED4亮,再次按5设置时间可以灭灯
---------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;

entity clock IS
PORT(clk:IN  STD_LOGIC;
     SEG_LED:OUT STD_LOGIC_VECTOR(6 downto 0);--数码管的七段
     SEG_NCS:OUT STD_LOGIC_VECTOR(5 downto 0);--4个数码管的选通
	  segdot:OUT STD_LOGIC:='0';--常亮
	  key1:IN STD_LOGIC;    --选择显示时间
	  key2:IN STD_LOGIC;     --选择秒表
	  key3:IN STD_LOGIC;     --选择闹钟
	  key4:IN STD_LOGIC;		--选择计时器
	  key5:IN STD_LOGIC;    
	  key6:IN STD_LOGIC;     
	  key7:IN STD_LOGIC;     
	  key8:IN STD_LOGIC;	 
	  led:out std_LOGIC:='1';--闹钟时间到灯亮
	  led_alarm_not_exit:out std_LOGIC:='1';--闹钟存在灯亮
	  led_count_down_clock:out std_LOGIC:='1'--倒计时时间到灯亮
 );
END clock;
ARCHITECTURE behav OF clock IS

SIGNAL bcddata:std_logic_vector(23 downto 0):=(others=>'0');  --初始化为0
SIGNAL bcddata_temp:std_logic_vector(23 downto 0):=(others=>'0');  --初始化为0
SIGNAL bcddata_Stopwatch:std_logic_vector(23 downto 0):=(others=>'0');  --初始化为0

--时钟模块的例化变量begin
SIGNAL clk_1s: STD_LOGIC :='0';          --初始化为0
SIGNAL clk_10ms: STD_LOGIC :='0';          --初始化为0
SIGNAL clkcnt:STD_LOGIC_VECTOR(30 DOWNTO 0):= (others =>'0');----初始化为0"00000000000000000";
--时钟模块的例化变量end
SIGNAL en :STD_LOGIC_VECTOR(1 DOWNTO 0):="00";--选择四种功能
SIGNAL key1_filt: STD_LOGIC ;     
SIGNAL key2_filt: STD_LOGIC ;
SIGNAL key3_filt: STD_LOGIC ;
SIGNAL key4_filt: STD_LOGIC ;
SIGNAL key5_filt: STD_LOGIC ;
SIGNAL skey5: STD_LOGIC :='0'; 
SIGNAL key6_filt: STD_LOGIC ;
SIGNAL skey6: STD_LOGIC :='0'; 
SIGNAL key7_filt: STD_LOGIC ;
SIGNAL skey7: STD_LOGIC :='0'; 
SIGNAL key8_filt: STD_LOGIC ;
SIGNAL skey8: STD_LOGIC :='0'; 
signal cs_clk_1s:std_LOGIC:='1';
--显示时间的变量
signal set_time:std_LOGIC:='0';
signal set_time_finish:std_LOGIC:='0';
signal move_left:std_LOGIC:='0';--时间显示和闹钟均用到
signal add:std_LOGIC:='0';--时间显示和闹钟均用到
signal sub:std_LOGIC:='0';--时间显示和闹钟均用到
signal position:integer range 0 to 20:=0;--时间显示和闹钟均用到
--秒表的变量
signal Stopwatch_begin:std_LOGIC:='0';
signal Stopwatch_clear:std_LOGIC:='0';
signal Stopwatch_save:std_LOGIC:='0';
signal Stopwatch_read:std_LOGIC:='0';
SIGNAL Stopwatch_save_data:std_logic_vector(23 downto 0):=(others=>'0');  --初始化为0
signal Stopwatch_show_savedata:std_LOGIC:='0';
--闹钟的变量
SIGNAL bcddata_alarm:std_logic_vector(23 downto 0):=(others=>'0');  --初始化为0
signal alarm_turn_off:std_LOGIC:='0';--闹钟响时关闭
signal alarm_clear:std_LOGIC:='1';--清除闹钟,初始化为关闭闹钟
signal led_blink:std_LOGIC:='0';
signal alarm_select:std_LOGIC:='0';
signal alarm_key5:std_LOGIC:='0';
SIGNAL bcddata_alarm_finally:std_logic_vector(23 downto 0):=(others=>'0');  --初始化为0
--计时器变量
signal count_down_clock_skey5:std_LOGIC:='0';
signal count_down_clock_begin:std_LOGIC:='0';
signal count_down_clock_select:std_LOGIC:='0';
SIGNAL bcddata_count_down_clock:std_logic_vector(23 downto 0):=(others=>'0');  --初始化为0
SIGNAL bcddata_count_down_clock_temp:std_logic_vector(23 downto 0):=(others=>'0'); 
signal led_count_down_clock_turn_off:std_LOGIC:='0';
--声明要使用到的模块
---时钟模块申明begin---------
component clock_source is
PORT(clk:IN  STD_LOGIC;
     clk_1s:out std_LOGIC;
	  clk_10ms: out std_LOGIC;
	  clkcnt: buffer STD_LOGIC_VECTOR(30 DOWNTO 0):= (others =>'0');
     Stopwatch_clear: in std_LOGIC
 );
end component clock_source; 
---时钟模块申明end--------- 


---按键状态模块申明begin--------- 
component key_state is
PORT(clk:IN  STD_LOGIC;
     key1_filt:in std_LOGIC;
	  key2_filt:in std_LOGIC;
	  key3_filt:in std_LOGIC;
	  key4_filt:in std_LOGIC;
	  key5_filt:in std_LOGIC;
	  key6_filt:in std_LOGIC;
	  key7_filt:in std_LOGIC;
	  key8_filt:in std_LOGIC;
	  en: buffer std_logic_vector(1 downto 0);
	  skey5: buffer std_LOGIC;
	  alarm_key5: buffer std_LOGIC;
	  count_down_clock_skey5: buffer std_LOGIC;
	  skey6: out std_LOGIC;
	  skey7: out std_LOGIC;
	  skey8: buffer std_LOGIC
 );
end component key_state;
--按键状态模块申明end--------- 

---数码管显示模块声明begin---
component seg_display is
PORT(clk:IN  STD_LOGIC;
	  clk_1s: in std_LOGIC;
	  clkcnt: in STD_LOGIC_VECTOR(30 DOWNTO 0);
	  en:in std_logic_vector(1 downto 0);
	  bcddata: in std_logic_vector(23 downto 0);
	  set_time: in std_LOGIC;
	  bcddata_temp:in std_logic_vector(23 downto 0);
	  position: in integer range 0 to 20;
	  Stopwatch_show_savedata:in std_LOGIC:='0';
	  Stopwatch_save_data:in std_logic_vector(23 downto 0);
	  bcddata_Stopwatch:in std_logic_vector(23 downto 0);
	  bcddata_alarm:in std_logic_vector(23 downto 0);
	  alarm_select:in std_LOGIC:='0';
	  bcddata_count_down_clock:in std_logic_vector(23 downto 0);
	  count_down_clock_select:in std_LOGIC;
	  segdot:OUT STD_LOGIC;
	  SEG_LED:OUT STD_LOGIC_VECTOR(6 downto 0);
     SEG_NCS:OUT STD_LOGIC_VECTOR(5 downto 0)
 );
end component seg_display;
---数码管显示模块声明end---

---按键消抖模块声明begin--
component keyfilt is
port (clk  : in  std_logic;
		key1 : in  std_logic;
		key1_filt : out std_logic;
		key2 : in  std_logic;
		key2_filt : out std_logic;
		key3 : in  std_logic;
		key3_filt : out std_logic;		
		key4 : in  std_logic;
		key4_filt : out std_logic;
		key5 : in  std_logic;
		key5_filt : out std_logic;
		key6 : in  std_logic;
		key6_filt : out std_logic;
		key7 : in  std_logic;
		key7_filt : out std_logic;
		key8 : in  std_logic;
		key8_filt : out std_logic
		);
end component keyfilt;
---按键消抖模块声明end--


---led控制模块申明begin--
component led_contro is
port (clk  : in  std_logic;
	   alarm_clear: in std_logic;
		led_alarm_not_exit: out std_logic;
		count_down_clock_select: in std_logic;
		bcddata_count_down_clock:in std_logic_vector(23 downto 0);
		led_count_down_clock:out std_logic
		);
end component led_contro;
---led控制模块申明end--
begin
--例化按键消抖模块begin---
akeyfilt: keyfilt port map
 (
		clk =>clk,
		key1=>key1,
		key1_filt =>key1_filt,
		key2=>key2,
		key2_filt =>key2_filt,
 		key3=>key3,
		key3_filt =>key3_filt,
		key4=>key4,
		key4_filt =>key4_filt,
		key5=>key5,
		key5_filt =>key5_filt,
		key6=>key6,
		key6_filt =>key6_filt,
		key7=>key7,
		key7_filt =>key7_filt,	
		key8=>key8,
		key8_filt =>key8_filt
 );
--例化按键消抖模块end---


---时钟模块例化begin---------
aclock_source: clock_source port map
(
	  clk=>clk,
     clk_1s=>clk_1s,
	  clk_10ms=>clk_10ms,
     Stopwatch_clear=>Stopwatch_clear,
	  clkcnt=>clkcnt
 );
---时钟模块例化end---------

---按键状态模块例化begin---------
akey_state: key_state port map
(
     clk=>clk,
     key1_filt=>key1_filt,
	  key2_filt=>key2_filt,
	  key3_filt=>key3_filt,
	  key4_filt=>key4_filt,
	  key5_filt=>key5_filt,
	  key6_filt=>key6_filt,
	  key7_filt=>key7_filt,
	  key8_filt=>key8_filt,
	  en=>en,
	  skey5=>skey5,
	  alarm_key5=>alarm_key5,
	  count_down_clock_skey5=>count_down_clock_skey5,
	  skey6=>skey6,
	  skey7=>skey7,
	  skey8=>skey8
 );
---按键状态模块例化end---------

---数码管显示模块例化begin---
aseg_display: seg_display port map
(
	  clk=>clk,
	  clk_1s=>clk_1s,
	  clkcnt=>clkcnt,
	  en=>en,
	  bcddata=>bcddata,
	  set_time=>set_time,
	  bcddata_temp=>bcddata_temp,
	  position=>position,
	  Stopwatch_show_savedata=>Stopwatch_show_savedata,
	  Stopwatch_save_data=>Stopwatch_save_data,
	  bcddata_Stopwatch=>bcddata_Stopwatch,
	  bcddata_alarm=>bcddata_alarm,
	  alarm_select=>alarm_select,
	  bcddata_count_down_clock=>bcddata_count_down_clock,
	  count_down_clock_select=>count_down_clock_select,
	  segdot=>segdot,
	  SEG_LED=>SEG_LED,
     SEG_NCS=>SEG_NCS
 );
---数码管显示模块例化end---


---例化led控制模块begin--
aled_contro: led_contro port map
(
		clk =>clk,
	   alarm_clear=>alarm_clear,
		led_alarm_not_exit=>led_alarm_not_exit,
		count_down_clock_select=>count_down_clock_select,
		bcddata_count_down_clock=>bcddata_count_down_clock,
		led_count_down_clock=>led_count_down_clock
);
---例化led控制模块end--
process(clk)
begin
	if(clk'event and clk='1') then
		case en is
		when "00" =>
						if(skey5='1') then
							set_time<='1';
							--set_time_finish<='0';
							--if(key5_filt='1') then
								--set_time_finish<='1';--只有在set_time=1时才为1
							--end if;
							if(key6_filt='1')then
								move_left<='1';
							else
								move_left<='0';
							end if;
							if(key7_filt='1')then
								add<='1';
							else
								add<='0';
							end if;
							if(key8_filt='1')then
								sub<='1';
							else
								sub<='0';
							end if;
						else
							set_time<='0';
							--set_time_finish<='0';
							--闹钟的关闭、清除
							if(key7_filt='1')then
								alarm_turn_off<='1';
							else
								alarm_turn_off<='0';
							end if;
						   if(key8_filt='1')then
							   alarm_clear<=not alarm_clear;
						   end if;	
						end if;
		when "01" =>
						if(key5_filt='1') then --开始计数,可暂停,不关闭时钟
							Stopwatch_begin<=not Stopwatch_begin;
						end if;
						if(key6_filt='1') then --清零键,关闭时钟
							Stopwatch_clear<=not Stopwatch_clear;
						end if;
						if(key7_filt='1') then --标记键
							Stopwatch_save<='1';
						else
							Stopwatch_save<='0';
						end if;
						if(skey8='1') then --读取键,再按一次返回秒表显示
							Stopwatch_read<='1';
						else
							Stopwatch_read<='0';
						end if;		
		when "10"=>	
						if(alarm_key5='1')then
							alarm_select<='1';--只是用来让闹钟界面数字不再闪烁,有没有确定实际上还是由alarm_clear决定
						else
							alarm_select<='0';
						end if;	
						if(key6_filt='1')then
							move_left<='1';
						else
							move_left<='0';
						end if;
						if(key7_filt='1')then
							add<='1';
						else
							add<='0';
						end if;
						if(key8_filt='1')then
							sub<='1';
						else
							sub<='0';
						end if;		
		when "11"=>
						if(count_down_clock_skey5='1') then--开始计时按钮
							count_down_clock_select<='1';
							if(key7_filt='1') then --在设定完时间的状态下检测7按键,按下则灭灯
								led_count_down_clock_turn_off<='1';
							else 
								led_count_down_clock_turn_off<='0';
							end if;
						else
							count_down_clock_select<='0';
						end if;
						if(key6_filt='1')then
							move_left<='1';
						else
							move_left<='0';
						end if;
						if(key7_filt='1')then
							add<='1';
						else
							add<='0';
						end if;
						if(key8_filt='1')then
							sub<='1';
						else
							sub<='0';
						end if;	
		when others=>
						NULL;
		end case;					
	end if;	
end process;



process(clk)
begin
if(clk'event and clk='1') then
	case  en is
	when "00"=>
				if(set_time='0') then--没有设置时间时,将bcddata复制到bcddata_temp,是为了按下5时可以从现在时间开始设置
					bcddata_temp<=bcddata;
					position<=0;--清零,下一次设置时间时仍是秒个位闪烁
					if(bcddata=bcddata_alarm_finally and alarm_clear='0') then
						led<='0';--闹钟时间到,led闪烁
					end if;
					if(alarm_turn_off='1') then
						led<='1';
					end if;
					
				end if;
				if(set_time='1') then 
					if(move_left='1')then
						if(position=20) then
							position<=0;
						else
						   position<=position+4;
						end if;
					end if;
					if(add='1')then
						if(position=0) then
							if(bcddata_temp(position+3 downto position)=9) then 
								bcddata_temp(position+3 downto position)<=x"9";
							else
								bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)+1;
							end if;
						elsif(position=4) then
							if(bcddata_temp(position+3 downto position)=5) then 
								bcddata_temp(position+3 downto position)<=x"5";
							else
								bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)+1;
							end if;
						elsif(position=8) then
							if(bcddata_temp(position+3 downto position)=9) then 
								bcddata_temp(position+3 downto position)<=x"9";
							else
								bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)+1;
							end if;
						elsif(position=12) then
							if(bcddata_temp(position+3 downto position)=5) then 
								bcddata_temp(position+3 downto position)<=x"5";
							else
								bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)+1;
						   end if;
						elsif(position=16) then
							if(bcddata_temp(23 downto 20)=0 or bcddata_temp(23 downto 20)=1) then
								if(bcddata_temp(position+3 downto position)=9) then 
									bcddata_temp(position+3 downto position)<=x"9";
								else
									bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)+1;
								end if;
							else
								if(bcddata_temp(position+3 downto position)=3) then 
									bcddata_temp(position+3 downto position)<=x"3";
								else
									bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)+1;	
	                     end if;							
							end if;
						else
							if(bcddata_temp(position+3 downto position)=2) then 
								bcddata_temp(position+3 downto position)<=x"2";
							else
								bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)+1;
							end if;
						end if;
					end if;
					if(sub='1')then
						if(bcddata_temp(position+3 downto position)=0) then 
							bcddata_temp(position+3 downto position)<=x"0";
						else
							bcddata_temp(position+3 downto position)<=bcddata_temp(position+3 downto position)-1;
						end if;
					end if;		
				end if;
	when "01"=>
					if(Stopwatch_save='1') then
						Stopwatch_save_data<=bcddata_Stopwatch;
					end if;
					if(Stopwatch_read='1') then
						Stopwatch_show_savedata<='1';
					else 
						Stopwatch_show_savedata<='0';
					end if;
	when "10"=>
					if(alarm_select='0') then--只有在没有选定之前才可以更改闹钟数字
						if(move_left='1')then
							if(position=20) then
								position<=0;
							else
								position<=position+4;
							end if;
						end if;
						if(add='1')then
							if(position=0) then
								if(bcddata_alarm(position+3 downto position)=9) then 
									bcddata_alarm(position+3 downto position)<=x"9";
								else
									bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)+1;
								end if;
							elsif(position=4) then
								if(bcddata_alarm(position+3 downto position)=5) then 
									bcddata_alarm(position+3 downto position)<=x"5";
								else
									bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)+1;
								end if;
							elsif(position=8) then
								if(bcddata_alarm(position+3 downto position)=9) then 
									bcddata_alarm(position+3 downto position)<=x"9";
								else
									bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)+1;
								end if;
							elsif(position=12) then
								if(bcddata_alarm(position+3 downto position)=5) then 
									bcddata_alarm(position+3 downto position)<=x"5";
								else
									bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)+1;
								end if;
							elsif(position=16) then
								if(bcddata_alarm(23 downto 20)=0 or bcddata_alarm(23 downto 20)=1) then
									if(bcddata_alarm(position+3 downto position)=9) then 
										bcddata_alarm(position+3 downto position)<=x"9";
									else
										bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)+1;
									end if;
								else
									if(bcddata_alarm(position+3 downto position)=3) then 
										bcddata_alarm(position+3 downto position)<=x"3";
									else
										bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)+1;	
									end if;							
								end if;
							else
								if(bcddata_alarm(position+3 downto position)=2) then 
									bcddata_alarm(position+3 downto position)<=x"2";
								else
									bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)+1;
								end if;
							end if;
						end if;
						if(sub='1')then
							if(bcddata_alarm(position+3 downto position)=0) then 
								bcddata_alarm(position+3 downto position)<=x"0";
							else
								bcddata_alarm(position+3 downto position)<=bcddata_alarm(position+3 downto position)-1;
							end if;
						end if;
					end if;
					if(alarm_select='1') then 
						position<=0;
						bcddata_alarm_finally<=bcddata_alarm;
					else
						bcddata_alarm_finally<="111111111111111111111111";--让bcddata_alarm_finally不可能与bcddata相等,看起来好像没有选定就不能设置闹钟
					end if;
	when "11"=>
					if(count_down_clock_select='0') then--只有在没有选定之前才可以更改计时器数字
						if(move_left='1')then
							if(position=20) then
								position<=0;
							else
								position<=position+4;
							end if;
						end if;
						if(add='1')then
							if(position=0) then
								if(bcddata_count_down_clock_temp(position+3 downto position)=9) then 
									bcddata_count_down_clock_temp(position+3 downto position)<=x"9";
								else
									bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)+1;
								end if;
							elsif(position=4) then
								if(bcddata_count_down_clock_temp(position+3 downto position)=5) then 
									bcddata_count_down_clock_temp(position+3 downto position)<=x"5";
								else
									bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)+1;
								end if;
							elsif(position=8) then
								if(bcddata_count_down_clock_temp(position+3 downto position)=9) then 
									bcddata_count_down_clock_temp(position+3 downto position)<=x"9";
								else
									bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)+1;
								end if;
							elsif(position=12) then
								if(bcddata_count_down_clock_temp(position+3 downto position)=5) then 
									bcddata_count_down_clock_temp(position+3 downto position)<=x"5";
								else
									bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)+1;
								end if;
							elsif(position=16) then
								if(bcddata_count_down_clock_temp(23 downto 20)=0 or bcddata_count_down_clock_temp(23 downto 20)=1) then
									if(bcddata_count_down_clock_temp(position+3 downto position)=9) then 
										bcddata_count_down_clock_temp(position+3 downto position)<=x"9";
									else
										bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)+1;
									end if;
								else
									if(bcddata_count_down_clock_temp(position+3 downto position)=3) then 
										bcddata_count_down_clock_temp(position+3 downto position)<=x"3";
									else
										bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)+1;	
									end if;							
								end if;
							else
								if(bcddata_count_down_clock_temp(position+3 downto position)=2) then 
									bcddata_count_down_clock_temp(position+3 downto position)<=x"2";
								else
									bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)+1;
								end if;
							end if;
						end if;
						if(sub='1')then
							if(bcddata_count_down_clock_temp(position+3 downto position)=0) then 
								bcddata_count_down_clock_temp(position+3 downto position)<=x"0";
							else
								bcddata_count_down_clock_temp(position+3 downto position)<=bcddata_count_down_clock_temp(position+3 downto position)-1;
							end if;
						end if;
					else 
						position<=0;
					end if;
	when others=>NULL;		
	end case;
end if;
end process;


process(clk_1s)
begin
		  if (clk_1s'event and clk_1s='1') then
			  if(set_time='0') then
				  if bcddata(3 downto 0)=x"9" then                  --秒的个位(10进制)
					  bcddata(3 downto 0)<=x"0";    
				  else
					  bcddata(3 downto 0)<=bcddata(3 downto 0)+1;   
				  end if;
				
				  if bcddata(7 downto 0)=x"59" then                 --秒的十位(6进制)
					  bcddata(7 downto 0)<=x"00";    
				  elsif bcddata(3 downto 0)=x"9"  then 
					  bcddata(7 downto 4)<=bcddata(7 downto 4)+1;   
				  end if;
					
				  if bcddata(11 downto 0)=x"959" then                --分的个位(10进制)
					  bcddata(11 downto 0)<=x"000";    
				  elsif bcddata(7 downto 0)=x"59" then
					  bcddata(11 downto 8)<=bcddata(11 downto 8)+1;   
				  end if;
				
				  if bcddata(15 downto 0)=x"5959" then               --分的十位(六进制)
					  bcddata(15 downto 0)<=x"0000";    
				  elsif bcddata(11 downto 0) =x"959" then
					  bcddata(15 downto 12)<=bcddata(15 downto 12)+1;   
				  end if;
				  
				  if bcddata(19 downto 0)=x"95959" then               --小时的十位(10进制)
					  bcddata(19 downto 0)<=x"00000";    
				  elsif bcddata(15 downto 0) =x"5959" then
					  bcddata(19 downto 16)<=bcddata(19 downto 16)+1;   
				  end if;
				  
				  if bcddata(23 downto 0)=x"235959" then               --小时的十位
					  bcddata(23 downto 0)<=x"000000";    
				  elsif bcddata(19 downto 0) =x"95959" then
					  bcddata(23 downto 20)<=bcddata(23 downto 20)+1;   
				  end if;
		     else
			     bcddata<=bcddata_temp;--至关重要的一句,确保设置时间的时候每时每刻把数据覆盖给bcddata
			  end if;
------------------------------------			  
					if(count_down_clock_select='1') then 
							--倒计时程序
						  if(bcddata_count_down_clock=0) then 
							  --什么都不做
						  else
							  if bcddata_count_down_clock(3 downto 0)=x"0" then                  --秒的个位(10进制)
								  bcddata_count_down_clock(3 downto 0)<=x"9";    
							  else
								  bcddata_count_down_clock(3 downto 0)<=bcddata_count_down_clock(3 downto 0)-1;   
							  end if;
							
							  if bcddata_count_down_clock(7 downto 0)=x"00" then                 --秒的十位(6进制)
								  bcddata_count_down_clock(7 downto 0)<=x"59";    
							  elsif bcddata_count_down_clock(3 downto 0)=x"0"  then 
								  bcddata_count_down_clock(7 downto 4)<=bcddata_count_down_clock(7 downto 4)-1;   
							  end if;
								
							  if bcddata_count_down_clock(11 downto 0)=x"000" then                --分的个位(10进制)
								  bcddata_count_down_clock(11 downto 0)<=x"959";    
							  elsif bcddata_count_down_clock(7 downto 0)=x"00" then
								  bcddata_count_down_clock(11 downto 8)<=bcddata_count_down_clock(11 downto 8)-1;   
							  end if;
							
							  if bcddata_count_down_clock(15 downto 0)=x"0000" then               --分的十位(六进制)
								  bcddata_count_down_clock(15 downto 0)<=x"5959";    
							  elsif bcddata_count_down_clock(11 downto 0) =x"000" then
								  bcddata_count_down_clock(15 downto 12)<=bcddata_count_down_clock(15 downto 12)-1;   
							  end if;
							  
							  if bcddata_count_down_clock(19 downto 0)=x"00000" then               --小时的十位(10进制)
								  bcddata_count_down_clock(19 downto 0)<=x"95959";    
							  elsif bcddata_count_down_clock(15 downto 0) =x"0000" then
								  bcddata_count_down_clock(19 downto 16)<=bcddata_count_down_clock(19 downto 16)-1;   
							  end if;
							  
							  if bcddata_count_down_clock(23 downto 0)=x"000000" then               --小时的十位
								  bcddata_count_down_clock(23 downto 0)<=x"235959";    
							  elsif bcddata_count_down_clock(19 downto 0) =x"00000" then
								  bcddata_count_down_clock(23 downto 20)<=bcddata_count_down_clock(23 downto 20)-1;   
							  end if;
							  
							  
						 end if;
					else
						bcddata_count_down_clock<=bcddata_count_down_clock_temp;
					end if;
				
		  end if;


end process;


process(clk_10ms)
begin
	  if Stopwatch_clear = '1' then   --异步清零
			bcddata_Stopwatch(23 downto 0)<= x"000000";
	  else 
		  if clk_10ms'event and clk_10ms='1' and Stopwatch_begin='1' then
			  if bcddata_Stopwatch(3 downto 0)=x"9" then                  --百分秒的个位(十进制)
				  bcddata_Stopwatch(3 downto 0)<=x"0";    
			  else
				  bcddata_Stopwatch(3 downto 0)<=bcddata_Stopwatch(3 downto 0)+1;   
			  end if;
			
			  if bcddata_Stopwatch(7 downto 0)=x"99" then                 --百分秒的十位(十进制)
				  bcddata_Stopwatch(7 downto 0)<=x"00";    
			  elsif bcddata_Stopwatch(3 downto 0)=x"9"  then 
				  bcddata_Stopwatch(7 downto 4)<=bcddata_Stopwatch(7 downto 4)+1;   
			  end if;
				
			  if bcddata_Stopwatch(11 downto 0)=x"999" then                --秒的个位(十进制)
				  bcddata_Stopwatch(11 downto 0)<=x"000";    
			  elsif bcddata_Stopwatch(7 downto 0)=x"99" then
				  bcddata_Stopwatch(11 downto 8)<=bcddata_Stopwatch(11 downto 8)+1;   
			  end if;
			
			  if bcddata_Stopwatch(15 downto 0)=x"5999" then               --秒的十位(六进制)
				  bcddata_Stopwatch(15 downto 0)<=x"0000";    
			  elsif bcddata_Stopwatch(11 downto 0) =x"999" then
				  bcddata_Stopwatch(15 downto 12)<=bcddata_Stopwatch(15 downto 12)+1;   
			  end if;
			  
			  if bcddata_Stopwatch(19 downto 0)=x"95999" then               --小时的十位(10进制)
					bcddata_Stopwatch(19 downto 0)<=x"00000";    
			  elsif bcddata_Stopwatch(15 downto 0) =x"5999" then
					bcddata_Stopwatch(19 downto 16)<=bcddata_Stopwatch(19 downto 16)+1;   
			  end if;
							  
			  if bcddata_Stopwatch(23 downto 0)=x"595999" then               --小时的十位
				   bcddata_Stopwatch(23 downto 0)<=x"000000";    
		     elsif bcddata_Stopwatch(19 downto 0) =x"95999" then
			      bcddata_Stopwatch(23 downto 20)<=bcddata_Stopwatch(23 downto 20)+1;   
			  end if;
		  end if; -- end clk_10ms
	  end if; --end clear
end process;
end behav;

设计原理与分析:在顶层文件中,首先对各个模块进行声明,为了概念明确一些,各个模块中的变量名与顶层文件中的变量名是一样的。顶层文件的作用是先对按键检测模块产生的信号进行判断(273行开始的进程),在en为不同值的情况下分别对按键检测到的信号进行判断,不直接用按键检测到的信号去控制四个功能下的各种设置作用是因为四个功能所用的键都是BUT5BUT7。因此在顶层文件中添加一个进程实现en为00,01,10,11情况下信号的变化赋值。接下来对不同en情况下对应的bcddata进行赋值以及相应功能的实现(384行开始的进程)。以设置时间为例,在设置时间时,用到了一个position整形变量,这个变量的范围为020,每按一下按键,position+4,对应要设置的bcddata为bcddata(position+3 downto position).当position超过20时,让position赋值为0。最后的两个进程分别以1HZ与100HZ作为触发信号,在1HZ的进程中进行时间bcddata数值的变化以及计时器的倒计时的bcddata_count_down_clock的数值的变化。
三、技术流程图
1、功能流程图
FPGA数字钟设计_第1张图片

2、程序流程图
FPGA数字钟设计_第2张图片

四、仿真
1、仿真四个按键BUT1~BUT4按下时en的变化情况
激励文件主要部分为:
FPGA数字钟设计_第3张图片

仿真结果:
FPGA数字钟设计_第4张图片

2、仿真定时器时间到时LED变为低电平,即点亮。激励文件中按key4后按两下key7,再按key5确定,计时两秒后led_count_down_clock变为低电平。
FPGA数字钟设计_第5张图片
FPGA数字钟设计_第6张图片

你可能感兴趣的:(电子电路)