基于FPGA的多功能数字钟的设计摘要数字钟是采用数字电路实现对时、分、秒数字显示的计时装置,是人们日常生活中不可少的必需品。
本文介绍了应用FPGA芯片设计多功能数字钟的一种方案,并讨讨论了有关使用FPGA芯片和VHDL语言实现数字钟设计的技术问题。
关键词数字钟、分频器、译码器、计数器、校时电路、报时电路。
Design ofAbstractKeywords目录0.引言 (4)1.设计要求说明 (4)1.1设计要求 (4)1.2完成情况说明 (4)2.多功能数字钟的基本原理及其在FPGA中的设计与实现 (4)2.1计时电路 (5)2.2异步清零电路 (5)2.3校时、校分功能电路 (5)2.4报时电路 (6)2.5分频电路 (7)2.6闹钟及音乐闹铃电路 (9)2.7秒表计时电路 (15)2.8译码显示电路 (15)2.9逻辑总图 (16)3.设计感想 (17)参考文献 (17)0.引言数字集成电路的发展和石英晶体振荡器的广泛应用,使得数字钟的精度远远超过老式钟表。
钟表的数字化给人们生产生活带来了极大的方便而且大大地扩展了钟表原先的报时功能。
因此,研究数字钟及扩大其应用,有着非常现实的意义。
1.设计要求说明1.1设计要求1)设计一个具有校时、校分、清零,保持和整点报时功能的数字钟。
2)多数字钟采用层次化的方法进行设计,要求设计层次清晰、合理;构成整个设计的功能模块既可采用原理图方法实现,也可采用文本输入法实现。
3)数字钟的具体设计要求具有如下功能:①数字钟的最大计时显示23小时59分59秒;②在数字钟正常工作时可以进行快速校时和校分,即拨动开关K1可对小时进行校正,拨动开关K2可对分钟进行校正;③在数字钟正常工作情况下,可以对其进行不断电复位,即拨动开关K3可以使时、分、秒回零;④整点报时是要求数字钟在每小时整点来到前进行鸣叫,鸣叫频率是在59分53秒、55秒、57秒时为500Hz,59分59秒时为1KHz;⑤哟啊去所有开关具有去抖动功能。
4)对设计电路进行功能仿真。
5)将仿真通过的逻辑电路下载到EDA实验系统,对其进行验证。
1.2完成情况说明:对于实验要求的基本功能我们设计的电路都能准确实现。
另外,我们还附加了显示星期、秒表、闹钟时间来时播放音乐等功能。
2.多功能数字钟的基本原理及其在FPGA中的设计与实现通过分析多功能数字钟的设计要求和所要实现的功能,应用层次化方法设计出数字钟应由计时模块、分频脉冲模块、译码显示模块、校时校分和清零模块、报时模块等几个模块组成,其原理框图如下图1所示:图1 数字钟的原理框图2.1计时电路通过分析数字钟的功能,知道数字钟计时周期是24小时,因此必须设置模24的小时计数器,两个模为60的计数器实现分和秒的计数,三个计数器之间构成进为关系,即秒计数器为分计数器提供计数脉冲信号,分计数器为时计数器提供计数脉冲信号。
另外,如果想要数字钟还可以显示星期的话,还应添加一个模7的星期计数器,由时计数器提供计数脉冲信号。
从全局设计考虑计时器应具有使能端和异步清零端。
为实现计时功能,我们可以选用74160通过反馈清零法来构成模7、模24和模60计数器。
分别用2片74160做成1个模7计数器、1个模24计数器和2个模60计数器。
这4个计时器使用相同的1hz脉冲,将他们的进位端都连好,分计数器的个位的ENT 接59秒,时计数器的个位的ENT接59分59秒,星期计时器的ENT接23小时59分59秒。
由于是反馈清零法,所以将秒计数器、分计数器的状态60,时计数器的状态24,星期计数器的状态7分别接给各自的清零端,这样就可以实现计数功能了。
2.2异步清零电路为实现异步清零功能,可以将异步清零开关KK3分别和各个计数器的清零信号的取反相或非后再接给清零端。
这样,当KK3关闭(低电平)时,计数器正常计数;当开关KK3开启(高电平)时,计数器全部异步清零。
2.3校时、校分功能电路数字钟的校时和校分功能原理相同,通过开关KK1、KK2控制工作状态。
当KK1打到低电平、KK2打到低电平时,各计数器的ENT端接的都是正常计数信号,ENP端都是高电平,各个计数器均正常计数;当KK1打到高电平、KK2打到低电平时,分个计数器的ENP端接的是KK2的非(高电平),进位信号正常送入分十位计数器的ENT端,分计数器快速校分,而由于秒计数器和时计数器的个位的ENP 端接的是KK1的非,所以秒计数器和时计数器被保持;当KK1打到低电平、KK2打到高电平时,正常进位信号被阻塞,分计数器可以不接受秒计数器的进位信号控制,校时信号便被送入CP 端,时计数器可以进行快速校时。
以上3部分功能可放在同一模块中实现,电路图如2所示。
图2 计时、清零、校分校时电路仿真结果如下图3所示:图3 计时、清零、校分校时电路的仿真结果2.4报时电路数字钟的报时功能由两部分组成,一部分的作用是选择报时的时间,一部分的作用是选择报时的频率。
根据设计要求,数字钟在59分53秒、55秒、57秒的报时鸣叫频率为500Hz ,59分59秒的报时鸣叫频率为1KHz 。
用与非门控制蜂鸣器信号,电路计时到59分53秒、59分55、秒59分57秒时打开与门,把500Hz 信号送入蜂鸣器,到59分59秒时打开与门,把1KHz 信号送入蜂鸣器。
经卡诺图化简后,得二与门的输出表达式为: 4330302011595f s f s f s Y •••'''=这部分电路的电路图如下图4所示:图4 报时电路这部分功能仿真结果如图5所示:图5 报时电路仿真结果2.5分频电路数字钟计时的标准信号应该是频率相当稳定的1HZ秒脉冲,所以要设置标准时间源。
由于FPGA芯片上有输出频率是48MHz的高精确度、高频稳度的晶体振荡器,所以我们只需做一些特定模的计数器进行分频就可以得到我们所需要的精确频率。
分析电路中的功能,一共需做3种计数器来分频,分别模48、模1000和模2计数器。
它们均可由74161构成,运用反馈置数法可以很容易的做成这3种计数器。
模48的计数器如下图6所示:图6 48分频器电路其仿真结果如图7所示:图7 48分频器仿真结果模1000的计数器如下图8所示:图8 1000分频器电路器仿真结果如下图9所示:图9 1000分频器仿真结果模2的计数器如下图10所示:图10 2分频电路其仿真结果如图11所示:图11 2分频仿真结果2.6闹钟及音乐闹铃电路通过分析闹钟应具有的功能,可以清楚闹钟应分成这样几个部分来做。
一是设定闹钟时间(小时、分钟)电路,可以还用类似于校时、校分的方法,用控制计数开始计数和暂停来实现设定时间;二是比较电路当正常计时的数字钟的时间和设定的闹钟时间相同时,输出一高电平,使其与发声频率相与后送给蜂鸣器来发出声响;三是显示切换电路,这个电路保证在设定闹钟时间时,虽然数码管显示的是闹钟设定的时间,但数字钟还在正常计时,只是没有显示出来。
通过以上分析发现,闹钟时间设定模块可以直接利用前面设计好的计时&校时校分模块jishi.bdf,只要在原来基础上加3个开关去控制就可以了。
其中,KK4的作用是切换显示开关,将它与1hz脉冲相与后再接给闹钟计数器的时钟,KK4打开时,设定闹钟时间的计数器才使能;KK5是设定分钟计数器的开关;KK6是设定小时计数器的开关。
比较模块则可以用4片集成的数据比较器7485(时2片、分2片)来实现比较功能,将4片7485的输出AEBO(相等时输出1)通过4与门相与后再输出,只有当4个AEBO同时出1时才代表闹钟时间和时钟时间重合。
至于显示切换电路则可以用6片2选1数据选择器74157来构成一个2路选1路的数据选择器,用切换开关KK4来判断2路选1路的数据选择器的选择输出正常计时的时间给数码管显示,还是输出闹钟设定时间给数码管显示。
这3部分的电路如下图12所示。
图12 闹钟功能电路在上面闹钟的基础上,我们还增加了播放音乐的功能,即当到达设定的闹钟时刻时,蜂鸣器会播放出优雅的《梁祝》曲子。
这部分功能需要通过VHDL硬件语言来编写程序。
要实现播放音乐功能需要包含控制、曲谱等在内5个子模块。
程序源码如下:1)模块1-- File Name: music.vhdLIBRARY ieee;USE ieee.std_logic_1164.all;LIBRARY altera_mf;USE altera_mf.altera_mf_components.all;ENTITY music ISPORT(address : IN STD_LOGIC_VECTOR (7 DOWNTO 0);clock : IN STD_LOGIC ;q : OUT STD_LOGIC_VECTOR (3 DOWNTO 0));END music;ARCHITECTURE SYN OF music ISSIGNAL sub_wire0 : STD_LOGIC_VECTOR (3 DOWNTO 0);COMPONENT altsyncramGENERIC (intended_device_family : STRING;width_a : NATURAL;widthad_a : NATURAL;numwords_a : NATURAL;operation_mode : STRING;outdata_reg_a : STRING;address_aclr_a : STRING;outdata_aclr_a : STRING;width_byteena_a : NATURAL;init_file : STRING;lpm_hint : STRING;lpm_type : STRING);PORT (clock0 : IN STD_LOGIC ;address_a : IN STD_LOGIC_VECTOR (7 DOWNTO 0);q_a : OUT STD_LOGIC_VECTOR (3 DOWNTO 0) );END COMPONENT;BEGINq <= sub_wire0(3 DOWNTO 0);altsyncram_component : altsyncramGENERIC MAP (intended_device_family => "Cyclone",width_a => 4,widthad_a => 8,numwords_a => 256,operation_mode => "ROM",outdata_reg_a => "CLOCK0",address_aclr_a => "NONE",outdata_aclr_a => "NONE",width_byteena_a => 1,init_file => "speaker.mif",lpm_hint => "ENABLE_RUNTIME_MOD=NO",lpm_type => "altsyncram")PORT MAP (clock0 => clock,address_a => address,q_a => sub_wire0);END SYN;2)模块2-- File Name: notetabs.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity notetabs isport(clk:in std_logic;toneindex:out std_logic_vector(3 downto 0));end;architecture one of notetabs iscomponent musicport(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);begincnt8:process(clk)beginif counter=138 then counter<="00000000";elsif (clk'event and clk='1')then counter<=counter+1;end if;end process;u1:music port map(address=>counter,q=>toneindex,clock=>clk); end;3)模块3-- File Name: tonetaba.vhdlibrary ieee;use ieee.std_logic_1164.all;entity tonetaba isport(index:in std_logic_vector(3 downto 0);tone:out std_logic_vector(10 downto 0));end;architecture one of tonetaba isbeginsearch:process(index)begincase index iswhen "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;4)模块4-- File Name: speaker.vhdlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity speaker isport(clk:in std_logic;tone:in std_logic_vector(10 downto 0);spks:out std_logic);end entity speaker;architecture one of speaker issignal preclk,fullspks:std_logic;begindivideclk:process(clk)variable count4:std_logic_vector(3 downto 0);beginpreclk<='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);beginif preclk'event and preclk='1' thenif 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;beginif 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;5)模块5-- File Name: songer.vhdlibrary ieee;use ieee.std_logic_1164.all;entity songer isport(clk12MHZ:in std_logic;clk8HZ:in std_logic;spkout:out std_logic);end;architecture one of songer iscomponent notetabsport(clk:in std_logic;toneindex:out std_logic_vector(3 downto 0));end component;component tonetabaport(index:in std_logic_vector(3 downto 0);tone:out std_logic_vector(10 downto 0));end component;component speakerport(clk: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);beginu1:notetabs port map(clk=>clk8HZ,toneindex=>toneindex);u2:tonetaba port map(index=>toneindex,tone=>tone);u3:speaker port map(clk=>clk12MHZ,tone=>tone,spks=>spkout);end;将上面5个程序输入好后分别编译,然后再将模块5songer.vhd生成芯片,再将这块芯片添加到闹钟电路里,就可以播放梁祝音乐闹铃了。