关键字:电子钟、FPGA、VHDL语言
前言:现在电子钟产品可谓百家争鸣,市场上到处可见一些功能齐全的设备,可能基于单片机的比较多,用FPGA设计电子钟可能比较少。因为两个都可以实现同样的功能,而FPGA 芯片的价格远比单片机高。出于利润,当然会选择开发成本少的产品。本次设计的目的是为了检验所学的知识(VHDL语言)同时结合实践巩固知识,由于初涉该领域,相关的知识可能不够全面,实践的经验不够,所以本设计旨在能够实现该功能并达到一定的精度,对于各模块设计的优化和性能等方面没有多加考虑。为提高精度,所以本设计采用12MHZ的CLK信号,这样产生的误差也较小。
一、设计目的
1、掌握各类计数器及将它们相连的方法;
2、掌握多个数码管动态显示的原理和方法
3、掌握FPGA技术层次化设计
4、进一步了解VHDL硬件描述语言的设计思想
5、了解有关数字系统的设计
二、设计原理:
数字钟电路的基本结构由两个60进制计数器和一个24进制计数器组成,分别对秒、分、小时进行计时,当计时到23时59分59秒时,再来一个计数脉冲,则计数器清零,重新开始计时。秒计数器的计数时钟CLK为1Hz的标准信号,可以由晶振产生的24 MHz信号通过分频得到。当数字钟处于计时状态时,秒计数器的进位输出信号作为分钟计数器的计数信号,分钟计数器的进位输出信号又作为小时计数器的计数信号时、分、秒的计时结果通过6个数码管来动态显示。数字钟除了能够正常计时外,还应能够对时间进行调整。因此,通过模式选择信号MOD1、MOD2控制数字钟的工作状态,即控制数字钟,使其分别工作于正常计时,调整分、时和设定分、时5个状态。当数字钟处于计时状态时,3个计数器允许计数,且秒、分、时计数器的计数时钟信号分别为CLK,秒的进位, 分的进位;当数字钟处于调整时间状态时,被调的分或时会一秒一秒地增加;当数字钟处于定时状态时,可以设定小时和分;当计时到所设定的时刻时,speak将会被赋予1KHz的脉冲信号用于驱动扬声器,持续1分钟。
三、电子钟相关功能描述如下:
(1) 计时功能:这是本计时器设计的基本功能,可进行时、分、秒计时,并显示。
(2) 闹钟功能:如果当前时间与设置的闹钟时间相同,则扬声器发出一段音乐,并维持一分钟。
(3) 调时调分调闹钟功能:当需要校时或者要重新设置闹钟的时间时,可通过实验箱上的按键控制。
四、实现涉及的几个重要模块如下:
(1)分频器将较高速的外部时钟频率分频成每分钟一次的时钟频率,以便进行时钟计数。
(2) 计数器实际上是一个异步复位、异步置数的累加器,通常情况下进行时钟累加计数,必要时可置入新的时钟值,然后从该值开始新的计数。
(3 寄存器用于保存用户设置的闹钟时间,是一个异步复位寄存器。
(4) 显示器根据需要显示当前时间、用户设置的闹钟时间或用户通过键盘输入的新的时间,同时判断当前时间是否已到了闹钟时间,实际上是一个多路选择器加比较器。
(5) 控制器是设计的核心部分,按设计要求产生相应的控制逻辑,以控制其他各部分的工作。
(6)乐曲演奏电路,实现闹钟的功能,那时间就发出一段叫“梁祝”的乐音。
实验代码:
1)主程序模块:
library ieee;use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
entity szz is
port(clk:in std_logic;
md1:in std_logic;
md2:in std_logic_vector(1 downto 0);
speak:out std_logic;
h1,h2,m1,m2,s1,s2:out std_logic_vector(3 downto 0));
end szz;
architecture one of szz is
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);
begin
-----------------------------------------------小时十位
h110:process(clk,hou2,min1,min2,sec1,sec2,md1,md2)
begin
if clk'event and clk='1' then
if (hou1="0010" and hou2="0011")and(min1="0101" and min2="1001")
and (sec1="0101" and sec2="1001") then
hou1<="0000";
elsif hou1="0010"and hou2="0011"and md1='0'
and md2="01" then--当时间为23点且处于校时状态时
hou1<="0000";
elsif (hou2="1001"and(min1="0101" and min2="1001")
and (sec1="0101" and sec2="1001"))or (hou2="1001"and md1='0' and md2="01") then
hou1<=hou1+1;
end if;
end if;
end process h110;
-----------------------------------------------小时个位
h220:process(clk,min1,min2,sec1,sec2,md1,md2,hou1)
beginif clk'event and clk='1' then
if (hou1="0010" and hou2="0011")and(min1="0101" and min2="1001") and (sec1="0101" and sec2="1001") then
hou2<="0000";
elsif hou2="1001"and(min1="0101" and min2="1001")
and (sec1="0101" and sec2="1001") then
hou2<="0000";
elsif (hou2="1001"and md1='0' and md2="01")
or (hou1="0010"and hou2="0011") then
hou2<="0000";--md<='1';
elsif ((min1="0101" and min2="1001") and (sec1="0101" and sec2="1001")) or (md1='0' and md2="01") then
hou2<=hou2+1;--speak<=clk;
end if;
end if;
end process h220;
-----------------------------------------------分钟十位
m110:process(clk,min2,sec1,sec2,md1,md2)
begin
if clk'event and clk='1' then
if (min1="0101" and min2="1001") and (sec1="0101" and sec2="1001") then min1<="0000";
elsif min1="0101"and min2="1001"and (md1='0' and md2="00")then
min1<="0000";
elsif (min2="1001"and (sec1="0101" and sec2="1001"))
or (min2="1001"and md1='0' and md2="00")then
min1<=min1+1;
end if;
end if;--end if;
end process m110;
----------------------------------------------分钟个位
m220:process(clk,sec1,sec2,md1,md2)
begin
if clk'event and clk='1' then
if min2="1001"and (sec1="0101" and sec2="1001")then
min2<="0000";
elsif min2="1001"and (md1='0' and md2="00")then
min2<="0000";
else if (sec1="0101" and sec2="1001") or(md1='0' and md2="00")then min2<=min2+1;
end if;end if;end if;
end process m220;
---------------------------------------------秒十位
s110:process(clk)
begin
if clk'event and clk='1' then
if (sec1="0101" and sec2="1001")then
sec1<="0000";
else if sec2="1001"then
sec1<=sec1+1;
end if;
end if;end if;
end process s110;
--------------------------------------------秒个位
s220:process(clk)
begin
if clk'event and clk='1' then
if sec2="1001" then
sec2<="0000";
else sec2<=sec2+1;
end if;
end if;
end process s220;
-------------------------------------------时间设置小时部分sethour1:process(clk,seth2)
begin
if clk'event and clk='1' then
if seth1="0010"and seth2="0011" then
seth1<="0000";
elsif seth2="1001" then
seth1<=seth1+1;
end if;
end if;
end process sethour1;
------------------------------------------
sethour2:process(clk,md1,md2,seth1)
begin
if clk'event and clk='1' then
if (seth1="0010"and seth2="0011")or seth2="1001"then seth2<="0000";
elsif md1='1' and md2="00" thenseth2<=seth2+1;
end if;
end if;
end process sethour2;
-------------------------------------------时间设置分钟部分
setmin1:process(clk,setm2)
begin
if clk'event and clk='1' then
if setm1="0101"and setm2="1001"then
setm1<="0000";
elsif setm2="1001"then
setm1<=setm1+1;
end if;
end if;
end process setmin1;
----------------------------------------------
setmin2:process(clk,md1,md2)
begin
if clk'event and clk='1'then
if setm2="1001"then
setm2<="0000";
elsif md1='1' and md2="01"then
setm2<=setm2+1;
end if;
end if;
end process setmin2;
--------------------------------------------
--------------------------------------------闹铃
speaker:process(clk,hou1,hou2,min1,min2)
begin
if clk'event and clk='1'then
if seth1=hou1 and seth2=hou2 and setm1=min1 and setm2=min2 then speak<=clk;
else speak<='0';
end if;
end if;
end process speaker;
-------------------------------------------
-------------------------------------------
disp:process(md1,hou1,hou2,min1,min2,sec1,sec2,seth1,seth2,setm1,setm2) begin
if md1='0' then---------------计时时间显示和设置模式
h1<=hou1;h2<=hou2;
m1<=min1;m2<=min2;
s1<=sec1;s2<=sec2;
else -----------闹铃时间现实和设置模式
h1<=seth1;h2<=seth2;
m1<=setm1;m2<=setm2;
s1<="1111";s2<="1111";
end if;
end process disp;
end one;
模块一,音乐演奏电路顶层设计
LIBRARY IEEE;
USE IEEE.STD_LOGIC_11.ALL;
ENTITY Songer IS
PORT ( CLK12MHZ,speak : IN STD_LOGIC;
CLK8HZ : IN STD_LOGIC;
SPKOUT : OUT STD_LOGIC );
END;
ARCHITECTURE behav OF Songer IS
COMPONENT NoteTabs IS
PORT ( CLK : IN STD_LOGIC;
ToneIndex : OUT STD_LOGIC_VECTOR (3 DOWNTO 0) ); END COMPONENT;
COMPONENT ToneTaba IS
PORT ( Index : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
Tone : OUT STD_LOGIC_VECTOR (10 DOWNTO 0) ); END COMPONENT;
COMPONENT Speakera
PORT ( clk ,en:IN STD_LOGIC;
Tone : IN STD_LOGIC_VECTOR (10 DOWNTO 0);
SpkS : OUT STD_LOGIC );
END COMPONENT;
SIGNAL Tone :STD_LOGIC_VECTOR (10 DOWNTO 0);
SIGNAL ToneIndex : STD_LOGIC_VECTOR (3 DOWNTO 0);U1 : NoteTabs PORT MAP (clk=>CLK8HZ, ToneIndex=>ToneIndex);
U2 : ToneTaba PORT MAP (Index=>ToneIndex, Tone=>Tone );
U3:SpeakeraPORTMAP(clk=>CLK12MHZ,Tone=>Tone,SpkS=>SPKOUT,en=>speak ); END;
模块二、
library ieee;
use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
entity notetabs is
port(clk:in std_logic;
speak:in std_logic;
toneindex:out std_logic_vector(3 downto 0));
end;
architecture one of notetabs is
component music
port(address:in std_logic_vector(7 downto 0);
clock:in std_logic;
q:out std_logic_vector(3 downto 0));
end component;
signal counter:std_logic_vector(7 downto 0);
begin
cnt8:process(clk,speak)
begin
if counter=138 then counter<="00000000";
elsif (clk'event and clk='1')then if speak='1' then counter<=counter+1;
else counter<=counter;
end if;end if;
end process;
u1:music port map(address=>counter,q=>toneindex,clock=>clk);
end;
模块三、
library ieee;
use ieee.std_logic_11.all;
entity tonetaba is
port(index:in std_logic_vector(3 downto 0);
tone:out std_logic_vector(10 downto 0));
end;
architecture one of tonetaba is
begin
search:process(index)case index is
when "0000"=>tone<="11111111111";
when "0001"=>tone<="01100000101";
when "0010"=>tone<="01110010000";
when "0011"=>tone<="10000001100";
when "0101"=>tone<="10010101101";
when "0110"=>tone<="10100001010";
when "0111"=>tone<="10101011100";
when "1000"=>tone<="10110000010";
when "1001"=>tone<="10111001000";
when "1010"=>tone<="11000000110";
when "1100"=>tone<="11001010110";
when "1101"=>tone<="11010000100";
when "1111"=>tone<="11011000000";
when others=>null;
end case;
end process;
end;
模块四、
library ieee;
use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
entity speakera is
port(clk:in std_logic;
tone:in std_logic_vector(10 downto 0);
spks:out std_logic);
end entity speakera;
architecture one of speakera is
signal preclk,fullspks:std_logic;
begin
divideclk:process(clk)
variable count4:std_logic_vector(3 downto 0);
begin
preclk<='0';
if count4>11 then preclk<='1';count4:="0000";
elsif clk'event and clk='1' then count4:=count4+1;
end if;
end process divideclk;
genspks:process(preclk,tone)
variable count11:std_logic_vector(10 downto 0);if preclk'event and preclk='1' then
if count11=16#7ff# then count11:=tone;fullspks<='1';
else count11:=count11+1;fullspks<='0';
end if;
end if;
end process;
delayspks:process(fullspks)
variable count2:std_logic;
begin
if fullspks'event and fullspks='1' then count2:=not count2;
if count2='1' then
spks<='1';
else spks<='0';end if;
end if;
end process;
end;
六、实验结果:
本实验是以md2、md1为控制整个闹钟的校时,校分,校闹钟时、分,分别将md2[1],md2[0],md1,送到实验上的三个键,由这三个键来控制整个校时,校分,校闹钟时,校闹钟分的过程,加上分别连接的键叫A,B,C键,
则当A=0,B=1,C=0时是对时钟进行校时,时个位和时十位会以二十四进制循环自动增加;
当A=0,B=0,C=0时是对时钟进行校分,分个位和分十位会以六十进制循环增加,并且不对时进位;
当A=0,B=1,C=1时是对闹钟进行校时,闹钟时个位和时十位会以二十四进制循环自动增加;当A=0,B=0,C=1时是对闹钟进行校分,闹钟分个位和分十位会以六十进制循环增加,并且不对时进位;
而当A=1,B=0,C=0或者A=1,B=1,C=0是正常的计时时间,秒从零开始计时,每秒加一,当到达五十九在来一个脉冲后,秒十位和秒个位清零,从零开始直到六十一直循环,并且向分个位清零;分位的原理同秒的一样,计数到五十九后自动清零向时进位,而时与秒,分的不同之处是,当时计数到二十四时清零并且不向任何位进位。
另外当计数的时,分和闹钟所事先设置时,分相等时,“梁祝”这首歌会响起,作为闹钟并且维持一分钟,一分钟歌曲自动停止。
七、实验心得
通过这次实验我掌握各类计数器及将它们相连的方法,掌握多个数码管动态显示的原理和方法,掌握FPGA技术层次化设计,进一步了解VHDL硬件描述语言的设计思想,了解有关数字系统的设计。
课程论文
(FPGA原理与应用)
题目FPGA的电子钟设计(VHDL语言)
专业滨江信息工程2009级
学生姓名曹晓明
学号20092309039
得分下载本文