VHDL数字时钟设计
一、实验目的:
进一步练习VHDL语言设计工程的建立与仿真的步骤和方法、熟悉VHDL语言基本设计实体的编写方法。同时,在已有知识的基础上,简单综合编写程序,仿制简单器械。
二、实验环境:
PC个人计算机、Windows XP操作系统、Quartus II集成开发环境软件。
三、设计要求:
运用VHDL语言编写一个数字钟,具体要求:
1. 具有时、分、秒计数的十进制数字显示功能,以24小时循环计时。
2. 具有手动调节小时,分钟的功能。
3. 具有闹钟的功能,能够在设定的闹钟时间发出闹铃声。
四、实验步骤:
1. 定义输入输出信号量
port(
clk:in std_logic; ---时钟
speak:out std_logic; ---铃
dout:out std_logic_vector(7 downto 0); ---晶体管显示
setclk:in std_logic_vector(2 downto 0); ---操作按钮
d1,d2,d3,d4,d5,d6: out std_logic); ---六个晶体管
2. 定义结构体中的信号量
signal sel:std_logic_vector(2 downto 0);
signal hou1:std_logic_vector(3 downto 0); --时分秒的个位和十位
signal hou2:std_logic_vector(3 downto 0);
signal min1:std_logic_vector(3 downto 0);
signal min2:std_logic_vector(3 downto 0);
signal seth1:std_logic_vector(3 downto 0);
signal seth2:std_logic_vector(3 downto 0);
signal setm1:std_logic_vector(3 downto 0);
signal setm2:std_logic_vector(3 downto 0);
signal sec1:std_logic_vector(3 downto 0);
signal sec2:std_logic_vector(3 downto 0);
signal h1:std_logic_vector(3 downto 0);
signal h2:std_logic_vector(3 downto 0);
signal m1:std_logic_vector(3 downto 0);
signal m2:std_logic_vector(3 downto 0);
signal s1:std_logic_vector(3 downto 0);
signal s2:std_logic_vector(3 downto 0);
signal sph1,sph2,spm1,spm2,sps1,sps2:std_logic_vector(3 downto 0);
signal count_sec:std_logic_vector(9 downto 0);
signal sec_co :std_logic;
signal co1,co2,co3,co4:std_logic; --进位
signal switch :std_logic_vector(1 downto 0); --表示状态
3. 分频模块
用来定义秒count_sec用来计时钟个数,当count_sec=11时,及得到1Hz信号。代码如下: process (clk) is --define a second
begin
if(clk'event and clk='1')then
if(count_sec="11")then
count_sec<="0000000000";
sec_co<='1';
else
count_sec<=count_sec+'1';
sec_co<='0';
end if;
end if;
end process;
4.时钟正常走时模块
该模块使用6个进程实现,分别为秒个位计时、秒十位计时、分个位计时、分十位计时、时个位计时、时十位计时。
process(sec_co) is ------------秒个位
begin
if switch="00" then --正常状态
if sec_co='1' then
if sec2="1001" then
sec2<="0000";
co1<='1';
else
sec2<=sec2+'1';
co1<='0';
end if;
end if;
elsif switch="01" then --调时状态
sec2<="0000";
end if;
end process;
--------------------------------------------------
process (co1) is -------秒十位
if switch="00" then
if co1'event and co1='1' then
if (sec1="0101")then
sec1<="0000";
co2<='1';
else
sec1<=sec1+'1';
co2<='0';
end if;
end if;
elsif switch="01" then
sec1<="0000";
end if;
end process;
------------------------------------------------- process (co1,co2) is --------分钟个位
begin
if switch="00" then
if co2'event and co2='1' then
if min2="1001" then
min2<="0000";
co3<='1';
else
min2<=min2+'1';
co3<='0';
end if;
end if;
min2<=setm2;
end if;
end process;
------------------------------------------------------
process (co3) is -----------分钟十位
begin
if switch="00" then
if co3='1' then
if min1="0101" then
min1<="0000";
co4<='1';
else
min1<=min1+'1';
co4<='0';
end if;
end if;
elsif switch="01" then
min1<=setm1;
end if;
end process;
---------------------------------------------------------
process(co4) -------小时
begin
if switch="00" then
if co4='1' then
if (hou1="0010") then --小时十位为2时,个位满3进一if(hou2="0011")then
hou1<="0000";
else
hou2<=hou2+'1';
end if;
else --小时十位为0或1,个位满9进一
if(hou2="1001")then
hou2<="0000";
hou1<=hou1+'1';
else
hou2<=hou2+'1';
end if;
end if;
end if;
elsif switch="01" then
hou1<=seth1;
hou2<=seth2;
end if;
end process;
5.调时模块
该进程用来控制时钟状态,switch为“00”时正常显示时间,为“01”时是进行调时,
为“10”时是设置闹钟时间。代码如下:
process (setclk(0)) is
begin
if(setclk(0)'event and setclk(0)='1')then
if(switch="10")then
switch<="00";
switch<=switch+'1';
end if;
end if;
end process;
process (setclk(2),switch,setclk(1)) is
begin --setclk(1)为1调分
if(switch="01" and setclk(1)='1')then
if(setclk(2)'event and setclk(2)='1')then if(setm2="1001")then
setm2<="0000";
if(setm1="0101")then
setm1<="0000";
else
setm1<=setm1+'1';
end if;
else
setm2<=setm2+'1';
end if;
end if;
end if;
end process;
process (setclk(2),switch,setclk(1)) is
begin --setclk(1)为0调时
if(switch="01" and setclk(1)='0')then
if(setclk(2)'event and setclk(2)='1')then if(seth1="0010")then
seth1<="0000";
seth2<="0000";
else
seth2<=seth2+'1';
end if;
else
if(seth2="1001")then
seth1<=seth1+'1';
seth2<="0000";
else
seth2<=seth2+'1';
end if;
end if;
end if;
end if;
end process;
6.闹钟模块
该模块由3个小模块组成,分别为设置闹钟时间、判断闹钟时间是否到达以及闹铃声音模块。
(1)设置闹钟时间模块
该进程用于设置闹钟时间。
信号量switch为‘10‘时,表示设置闹钟时间;
if(switch="10")then --调闹钟时,显示闹钟设置时间
if sel="000" then
d1<='0';
case sph1 is
when "0000"=>dout<="";
when "0010"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="001" then
d2<='0';
case sph2 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when "0110"=>dout<="";
when "0111"=>dout<="";
when "1000"=>dout<="";
when "1001"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="010" then
d3<='0';
case spm1 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
elsif sel="011" then
d4<='0';
case spm2 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when "0110"=>dout<="";
when "0111"=>dout<="";
when "1000"=>dout<="";
when "1001"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="100" then
d5<='0';
case sps1 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
case sps2 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when "0110"=>dout<="";
when "0111"=>dout<="";
when "1000"=>dout<="";
when "1001"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
end if;
(2)闹铃声音模块
通过分频产生蜂鸣,即发出闹铃声音。
process (switch) is ------闹铃 begin --设置闹铃时秒归零
if switch="10" then
sps1<="0000";
sps2<="0000";
end if;
end process;
process (switch,setclk(2),setclk(1)) is begin
if(setclk(2)'event and setclk(2)='1')then if(spm2="1001")then
spm2<="0000";
if(spm1="0101")then
spm1<="0000";
else
spm1<=spm1+'1';
end if;
else
spm2<=spm2+'1';
end if;
end if;
end if;
end process;
process (switch,setclk(2),setclk(1)) is
begin
if(switch="10" and setclk(1)='0')then
if(setclk(2)'event and setclk(2)='1')then if(sph1="0010")then
if(sph2="0011")then
sph1<="0000";
sph2<="0000";
else
sph2<=sph2+'1';
end if;
else
if(sph2="1001")then
sph2<="0000";
sph1<=sph1+'1';
else
sph2<=sph2+'1';
end if;
end if;
end if;
end if;
end process;
process (clk,sph1,sph2,spm1,spm2,hou1,hou2,min1,min2) is begin
if(sph1=hou1 and sph2=hou2 and spm1=min1 and spm2=min2)then
speak<=clk;
else
speak<='0';
end if;
end process;
7.数码管显示模块
(1)选择时间显示
process(key1,key2,change)
begin
if(key1='0')and(key2='0')then
sec_0<=sec_00;
sec_1<=sec_11;
min_0<=min_00;
min_1<=min_11;
hour_1<=hour_11;
hour_0<=hour_00;
elsif(key1='1')and(key2='0')then sec_0<=sec_000;
sec_1<=sec_111;
min_0<=min_000;
min_1<=min_111;
hour_0<=hour_000;
hour_1<=hour_111;
elsif(key1='0')and(key2='1')then sec_0<=sec_0000;
sec_1<=sec_1111;
min_0<=min_0000;
min_1<=min_1111;
hour_0<=hour_0000;
hour_1<=hour_1111;
end if;
end process;
(2)数码管时间显示
if sel="000" then
d1<='0';
case h1 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="001" then
case h2 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when "0110"=>dout<="";
when "0111"=>dout<="";
when "1000"=>dout<="";
when "1001"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="010" then
d3<='0';
case m1 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="011" then
d4<='0';
case m2 is
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when "0110"=>dout<="";
when "0111"=>dout<="";
when "1000"=>dout<="";
when "1001"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="100" then
d5<='0';
case s1 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0010"=>dout<="";
when "0011"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
elsif sel="101" then
d6<='0';
case s2 is
when "0000"=>dout<="";
when "0001"=>dout<="";
when "0100"=>dout<="";
when "0101"=>dout<="";
when "0110"=>dout<="";
when "0111"=>dout<="";
when "1000"=>dout<="";
when "1001"=>dout<="";
when others=>dout<="XXXXXXXX";
end case;
end if;
五、实验结果分析总结:
该程序基本实现了数字时钟的基本功能,能够正常走时,并且可以校正时间,还可以进行闹钟设置。
通过这次VHDL课程设计,我学到了很多,对于原本掌握的不好的数字逻辑相关知识,在课程设计具体实践中有了很深刻的认识,在对于Quartus II的操作上也有很大的提高,增加了操作的熟练程度,现在我已经有信心做任何的设计课题。
在编程中还遇到其他一些小问题,有好多都是由于不够细心,不够严谨造成的,通过编程,我会一步步养成一个好的编程习惯,尽量避免一些不必要的错误,一步步提高自己。在今后的学习中,我还需要不断学习,不断锻炼自己。
六、附:源代码
library ieee;
use clock is
port(
clk:in std_logic; ---时钟
speak:out std_logic; ---铃
dout:out std_logic_vector(7 downto 0); ---晶体管显示
d1,d2,d3,d4,d5,d6: out std_logic); ---六个晶体管end entity clock;
architecture one of clock is
signal sel:std_logic_vector(2 downto 0);
signal hou1:std_logic_vector(3 downto 0); --时分秒的个位和十位signal hou2:std_logic_vector(3 downto 0);
signal min1:std_logic_vector(3 downto 0);
signal min2:std_logic_vector(3 downto 0);
signal seth1:std_logic_vector(3 downto 0);
signal seth2:std_logic_vector(3 downto 0);
signal setm1:std_logic_vector(3 downto 0);
signal setm2:std_logic_vector(3 downto 0);
signal sec1:std_logic_vector(3 downto 0);
signal sec2:std_logic_vector(3 downto 0);
signal h1:std_logic_vector(3 downto 0);
signal h2:std_logic_vector(3 downto 0);
signal m1:std_logic_vector(3 downto 0);
signal m2:std_logic_vector(3 downto 0);
signal s1:std_logic_vector(3 downto 0);
signal s2:std_logic_vector(3 downto 0);
signal sph1,sph2,spm1,spm2,sps1,sps2:std_logic_vector(3 downto 0);
signal count_sec:std_logic_vector(9 downto 0);
signal co1,co2,co3,co4:std_logic; --进位
signal switch :std_logic_vector(1 downto 0); --表示状态
begin
-------------------------------------------------
process (clk) is --define a second
begin
if(clk'event and clk='1')then
if(count_sec="11")then
count_sec<="0000000000";
sec_co<='1';
else
count_sec<=count_sec+'1';
sec_co<='0';
end if;
end if;
end process;
--------------------------------------------------
process(sec_co) is ------------秒个位
begin
if switch="00" then --正常状态
if sec_co='1' then
if sec2="1001" then
sec2<="0000";
co1<='1';
else
co1<='0';
end if;
end if;
elsif switch="01" then --调时状态
sec2<="0000";
end if;
end process;
--------------------------------------------------process (co1) is -------秒十位
begin
if switch="00" then
if co1'event and co1='1' then
if (sec1="0101")then
sec1<="0000";
co2<='1';
else
sec1<=sec1+'1';
co2<='0';
end if;
end if;
elsif switch="01" then
sec1<="0000";
end if;
end process;
-------------------------------------------------process (co1,co2) is --------分钟个位
begin