资源描述
数字闹钟
一、设计要求
设计一个数字闹钟,具有以下端口:
Input
Clock_1sec,Reset
LoadTime, SetHours, SetSecs, Set_AM_PM,
LoadAlm, AlarmHoursIn, AlarmMinsln, Alarm_AM_PM_In
AlarmEnable
output
Hours, Mins, Secs, Hours, AM_P, Flashing, Alarm
数字闹钟具有如下功能:
闹钟的输入是1s, 从Clock_1sec输入
闹钟基于12小时制,分为上午和下午。
LoadTime为高电平时,设定时间。
LoadAlm为高电平是,设定闹铃时间。
当前时间和设定的闹铃时间相同时,Alarm输出高电平。Alarm信号保持在高电平,直到AlarmEnable变为低电平(相当于关闭闹铃或者闹铃1分钟后)
当闹钟掉电后,然后又通电,应该显示“00:00:00”.Flashing信号变为高电平。这时候显示屏为空状态(flashing),表示闹钟要设定时间。Flashing信号维持高电平直到设定新的时间。
二、设计分析与设计思路
1、实验板硬件资源
看完题目,有了大概思路后,接下来第一步就是了解提供的实验板,以确定编程思路。
经过研究发现,此次实验板可以用到的开发板上的控制外设有:4个按键开关、4个拨码开关、4个数码管(此处按6位数码管设计)。
因此,可以初步这么决定,利用数码管显示时间,利用按键开关进行修改与设置的操作,利用拨码开关改变闹钟运行的模式,利用蜂鸣器发出各种提示音,利用发光LED表示闹钟运行的各种状态。
2、功能分析
修改时间或设置闹钟时能实现加1操作。
时钟走到设置时间时会响,正常模式时响1分钟。
3、确定开关功能
按键开关(对应板上按键从左至右分别为K1、K2、K3、K4和拨位开关K5、K6、K7、K8)
K1:重置时间和闹铃时间为00:00:00
K2:设置时钟
K3:设置闹铃
K4、k5、k6:修改或设置时间和闹钟状态下加1操作
K7:设置时间或闹铃的上午或者下午
K8:结束修改或设置时间和闹铃,开始计时
4、设计分析 在设计中考虑采用模块化的思想,将系统总的功能分解成若干个子功能。初步考虑分为3个部分:键盘部分、处理器部分和显示部分。键盘模块通过扫描按键开关和拨码开关得到操作信息,处理器模块通过键盘模块输入的操作信息处理数据,并加处理后的时间数据传给显示模块,由显示模块显示结果。结构框图如下:
三、各模块的设计与实现
1、键盘模块:keyboard
1、anjian1为7位键,包括四位按键和三位拨码;
2、Clock_hsec为2Hz的时钟。
3、Reset,
4、LoadTime,启动时间设置按键
5、SetHours, SetSecs, Set_AM_PM
为时间设置按键
6、LoadAlm, 启动时间设置按键
7、AlarmHoursIn,AlarmMinsln,Alarm_AM_PM_In
为闹铃设置按键
8、AlarmEnable 启动计时和闹铃
由8个开关组成的键盘通过不断扫描得到操作信息,送入数据处理器。
源代码如下:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity keybord is
port(
Clock_hsec:in std_logic;
anjian1:in bit_vector(6 downto 0);
Reset:out std_logic;
LoadTime:out std_logic;
SetHours:out std_logic;
SetSecs:out std_logic;
Set_AM_PM:out std_logic;
LoadAlm:out std_logic;
AlarmHoursIn:out std_logic;
AlarmMinsln:out std_logic;
Alarm_AM_PM_In:out std_logic;
AlarmEnable:out std_logic
);
end keybord;
architecture hebav of keybord is
signal key:std_logic_vector(6 downto 0);
begin
process(Clock_hsec,anjian1)
begin
if(Clock_hsec'event and Clock_hsec='1') then
case anjian1 is
when "0111111"=>key<="1000000";
when "1011111"=>key<="0100000";
when "1101111"=>key<="0010000";
when "1110111"=>key<="0001000";
when "1111011"=>key<="0000100";
when "1111101"=>key<="0000010";
when "1111110"=>key<="0000001";
when others=>key<="0000000";
end case;
end if;
end process;
Reset<=key(0);
LoadTime<=key(1);
LoadAlm<=key(2);
SetHours<=key(3);
SetSecs<=key(4);
Set_AM_PM<=key(5);
AlarmHoursIn<=key(3);
AlarmMinsln<=key(4);
Alarm_AM_PM_In<=key(5);
AlarmEnable<=key(6);
end hebav;
2、处理器模块:processor
如左图:
1、时钟脉冲信号:Clock_1sec
2、Reset,重置时间和闹铃为00:00:00
3、start,为开始计时按键
4、LoadTime,启动时间设置按键
5、SetHours, SetSecs, Set_AM_PM
为时间设置按键
6、LoadAlm, 启动时间设置按键
7、AlarmHoursIn , AlarmMinsln, Alarm_AM_PM_In为闹铃设置按键
8、AlarmEnable 启动闹铃
源代码如下:
library ieee;
USE IEEE.STD_LOGIC_ARITH.ALL;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity alarm is
port( Clock_1sec:in std_logic;
Reset:in std_logic;
start:in std_logic;
LoadTime:in std_logic;
SetHours:in std_logic;
SetMins:in std_logic;
Set_AM_PM:in std_logic;
LoadAlm:in std_logic;
AlarmHoursIn:in std_logic;
AlarmMinsIn:in std_logic;
AlarmAM_PM_In:in std_logic;
AlarmEnable:in std_logic;
Hours:out std_logic_vector(3 downto 0);
Mins:out std_logic_vector(5 downto 0);
Secs:out std_logic_vector(5 downto 0);
AM_PM:out std_logic;
Alarm:out std_logic;
Flashing:out std_logic
);
end alarm;
architecture behav of alarm is
signal Hourssjh:integer range 0 to 11:=0;
signal Minssjh:integer range 0 to 59:=0;
signal Secssjh:integer range 0 to 59:=0;
signal asjh:std_logic:='0';
signal Hourssj:integer range 0 to 11:=0;
signal Minssj:integer range 0 to 59:=0;
signal Secssj:integer range 0 to 59:=0;
signal asj:std_logic:='0';
signal Hourss:integer range 0 to 11:=0;
signal Minss:integer range 0 to 59:=0;
signal Secss:integer range 0 to 59:=0;
signal as:std_logic:='0';
signal Flash:std_logic:='1';
signal AL: std_logic:='0';
begin
Hours<= conv_std_logic_vector(Hourss,4);
Mins<= conv_std_logic_vector(Minss,6);
Secs<= conv_std_logic_vector(Secss,6);
AM_PM<=as;
Alarm<=AL;
Flashing<=Flash;
jishi:process(Clock_1sec)
begin
if (rising_edge(Clock_1sec))then
if (Reset='1')then --Reset
Secssjh<=0;
Minssjh<=0;
Hourssjh<=0;
asjh<='0';
Flash<='1';
elsif (start='1')then --start
Flash<='0';
elsif(Flash='0')AND(LoadTime='0')then --time
if(Secssjh<59)then
Secssjh<=Secssjh+1;
else
Secssjh<=0;
if(Minssjh<59)then
Minssjh<=Minssjh+1;
else
Minssjh<=0;
if(Hourssjh<11)then
Hourssjh<=Hourssjh+1;
else
Hourssjh<=0;
asjh<=not asjh;
end if;
end if;
end if;
elsif((LoadTime='1')and(LoadAlm='0'))then --set time
if SetHours='1' then
if(Hourssjh<11)then
Hourssjh<=Hourssjh+1;
else
Hourssjh<=0;
end if;
elsif SetMins='1' then
if(Minssjh<59)then
Minssjh<=Minssjh+1;
else
Minssjh<=0;
end if;
elsif Set_AM_PM='1' then
asjh<=not asjh;
end if;
end if;
end if;
end process;
process(Clock_1sec)
begin
if (rising_edge(Clock_1sec))then
if (Reset='1')then --alarm reset
Secssj<=0;
Minssj<=0;
Hourssj<=0;
asj<='0';
elsif(LoadAlm='1')then --set alarm
if AlarmHoursIn='1' then
if(Hourssj<11)then
Hourssj<=Hourssjh+1;
else
Hourssj<=0;
end if;
elsif AlarmMinsIn='1' then
if(Minssj<59)then
Minssj<=Minssj+1;
else
Minssj<=0;
end if;
elsif AlarmAM_PM_In='1' then
asj<=not asj;
end if;
end if;
end if;
end process;
process(Clock_1sec) --show time and alarm
begin
if (rising_edge(Clock_1sec))then
if(LoadAlm='0')then
Hourss<=Hourssjh;Minss<=Minssjh;Secss<=Secssjh;as<=asjh;
else
Hourss<=Hourssj;Minss<=Minssj;Secss<=Secssj;as<=asj;
end if;
end if;
end process;
process(Clock_1sec) --start alarm
begin
if (rising_edge(Clock_1sec))then
if(AlarmEnable='1' )then
if(Hourssjh=Hourssj)AND(Minssjh=Minssj)AND(asjh=asj)then
AL<='1';
else
AL<='0';
end if;
else
AL<='0';
end if;
end if;
end process;
end behav;
3、显示模块:display
源代码如下:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity display is
port(clk:in std_logic;
Mins, Secs:in integer range 0 to 59;
Hours:in integer range 0 to 12;
seg:out std_logic_vector(7 downto 0);
lsd:out std_logic_vector(5 downto 0));
end display;
architecture hebav of display is
signal cnt:integer range 0 to 5;
signal dis1:integer range 0 to 9;
signal dis2:integer range 0 to 9;
signal dis3:integer range 0 to 9;
signal dis4:integer range 0 to 9;
signal dis5:integer range 0 to 9;
signal dis6:integer range 0 to 9;
signal dis:integer range 0 to 9;
signal m:std_logic_vector(15 downto 0);
signal clk2:bit;
begin
dividefreq:process(clk)
begin
if(clk'event and clk='1') then
m<=m+'1';
if(m="1111111111111111") then
m<="0000000000000000";
clk2<=not clk2;
end if;
end if;
end process dividefreq;
disp:process(clk,dis1,dis2,dis3,dis4,dis5,dis6,Hours,Mins,Secs,cnt)
begin
if(clk'event and clk='1') then
dis2<=Hours mod 10;
dis1<=(Hours-dis2)/10;
dis4<=Mins mod 10;
dis3<=(Mins-dis4)/10;
dis6<=Secs mod 10;
dis5<=(Secs-dis6)/10;
end if;
if(cnt=0) then
dis<=dis1;
lsd<="011111";
cnt<=cnt+1;
elsif(cnt=1) then
dis<=dis2;
lsd<="101111";
cnt<=cnt+1;
elsif(cnt=2) then
dis<=dis3;
lsd<="110111";
cnt<=cnt+1;
elsif(cnt=3) then
dis<=dis4;
lsd<="111011";
cnt<=0;
elsif(cnt=4) then
dis<=dis4;
lsd<="111101";
cnt<=0;
elsif(cnt=5) then
dis<=dis4;
lsd<="111110";
cnt<=0;
end if;
case dis is
when 0=>seg<="00001100";
when 1=>seg<="01101111";
when 2=>seg<="10101000";
when 3=>seg<="00101001";
when 4=>seg<="01001011";
when 5=>seg<="00011001";
when 6=>seg<="00011000";
when 7=>seg<="01101101";
when 8=>seg<="00001000";
when 9=>seg<="00001001";
when others=>seg<="11111111";
end case;
end process;
end hebav;
4、分频模块 clkdiv
源代码如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY clkdiv IS
PORT(clk :IN STD_LOGIC;
Clock_1sec:OUT STD_LOGIC;
Clock_hsec:OUT STD_LOGIC);
END clkdiv;
ARCHITECTURE rtl OF clkdiv IS
SIGNAL count1,count2:STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL clk_temp1,clk_temp2:STD_LOGIC;
BEGIN
PROCESS(clk)
BEGIN
IF clk'event AND clk='1' THEN
IF(count1=25000000) THEN
count1 <= (OTHERS =>'0');
clk_temp1 <= NOT clk_temp1;
ELSE
count1 <= count1+1;
END IF ;
IF(count2=12500000) THEN
count2 <= (OTHERS =>'0');
clk_temp2 <= NOT clk_temp2;
ELSE
count2 <= count2+1;
END IF ;
END IF ;
END PROCESS;
Clock_1sec <= clk_temp1;
Clock_hsec <= clk_temp2;
END rtl;
五、仿真分析
一、 仿真结果
由于仿真时间过长或时钟频率过大会导致quartusII无法仿真,所以以下仿真均是在修改源程序时钟频率的前提下进行的。
核心模块:
分析:在最开始给reset发生变化,全部输出0,第8行flashing变高电平,知道loadtime产生一个上升沿,flashing变低电平,loadtime以前未作任何设置,所以默认从00:00:00开始走表,loadtime结束之后 loadalm有上升沿,loadalm为高电平期间,alarmminsin有一个上升沿,所以设置闹钟时间为00:01:00,在图像最右边显示了60秒之后分钟变化,当时间为00:01:00时,alarm变为高电平,在设置时间和闹钟时间时,由于初始化都未00:00:00所以打开开发板蜂鸣器就会响,第三行在loadalm之后,给alarm_enable一个上升沿,则alarm变为低电平,蜂鸣器停止响(这里和要求有些出入,但是原理完全一样,讲上升沿改成下降沿即可)。在loadalm期间,设置为00:01:00时,可以看到第26行的分钟低位输出为1,表明在设置闹钟时间时,显示的是设置闹钟时间,而非真正的时间。
二、 心得与思考
题目给出的输入输出接口,跟开发板上的可用资源不一样,所以如何把代码改为可以下载到开发板上实现,还需要花很多时间和精力才能完成。大概的思路是用开发板的四个七段数码管显示时间,可通过拨码开关在显示“时-分”和“分-秒”之间切换;用两个按键开关分别控制闹钟时间和闹铃时间的修改,用两个按键开关分别实现加1和减1的功能。Flashing接开发板的Flashing,Alarm接开发板的Beep。程序可分为键盘扫描模块、闹钟时间、闹铃时间设置和计时模块、闹铃闹响模块。
因为时间紧急,所以可以下载到开发板上的代码还没编完,所以先交找一个输入输出口跟题目给出的相同的程序。经功能仿真,能实现预期功能。
展开阅读全文