VHDL硬件描述语言是一门技术性、应用性很强的学科,学生不但能够将课堂上学到的理论知识与实际应用结合起来,而且能够对分析、解决实际问题的数字电路问题进一步加深认识,为今后能够独立进行某些数字应用系统的开发设计工作打下一定的基础。本次的设计是基于VHDL的实时时钟电路设计,完成时、分、秒的显示及调整设置功能。设计利用VHDL语言自顶向下的设计理念,突出其作为硬件描述语言的良好的可读性、可移植性以及易于理解等优点。通过QuartusII5.1和QuartusII12.1软件完成仿真、综合。程序下载到FPGA芯片后,可用于实际的数字钟显示。
2. 主要问题
进行实验的过程中有许多的问题,一开始不知道原理,对程序无从下手;编写过程中有语和定义错误,在模块调用时出现重复;不知道如何分配管脚以致调试错误。在分频模块的顺序添加上,在计时模块的小时分钟调节上,数码管的译码也遇到了问题。
3. 解决方法
在向老师和同学请教,查询相关资料以及网上查找以后,上述问题得以解决。
4. 最终结果
此次设计的逻辑结构主要由分频、计数和译码显示三个模块构成。分频模块将50MHz系统基准时钟分频产生时钟信号,由输入端控制输出时钟信号,有正常的计数功能。数字时钟计时工作模块,计时模块对1Hz的时钟信号进行计时,分为时、分、秒三个部分;最后通过主模块调用三个子模块函数实现整体设计要求。
实时时钟电路设计:
(1) 设计一个数码管实时显示时、分、秒的数字时钟(24小时显示模式);
(2) 为了演示方便,应具有分钟、小时快进功能;
(3) 时、分、秒的设置功能(选作)。
2 方案分析与总体设计
本次的设计是基于VHDL的实时时钟电路设计,完成时、分、秒的显示及调整功能。此次设计的逻辑结构主要由分频、计数、译码三个模块构成。分频模块将50MHz系统基准时钟分频产生两路时钟信号,一路是1Hz的数字钟计时工作频率,一路是数码管动态显示的扫描频率;计时模块对1Hz的时钟信号进行计时,分为时、分、秒三个部分,同时具有时分秒调整功能,方便演示;译码显示模块采用动态扫描的方式完成8个7位数码管的动态显示,最后通过主模块调用三个子模块实现整体设计要求。
综上,给出如下输入输出变量:
输入变量:1.时钟信号: 每个时钟的上升沿触发系统的状态转换;
2.计时复位信号:下降沿触发,按下后计时自动回到初始状态;
3.使能信号:激发时钟工作。
输出变量:1.数码管信号:按位输入到数码管,显示时钟;
2.计时时钟信号:分频后的计时时钟信号;
3.进位信号:进制转换。
3 各功能模块原理及实现
3.1 功能模块设计3.1.1 分频模块
1. 设计原理
本时钟电路的设计中使用DE2-115时钟芯片,故需对系统提供的50MHz时钟频率进行分频,得到计时所需的时钟频率。
定义变量并根据需要得到的分频信号设定计数值,对该变量进行加或减计数,每到达一次计数值点,将该变量清零或重置,并且对输出信号取一次反,即可以得到所需的分频信号。本模块采用此方法实现上述所需时钟信号的分频功能。
代码实现
library ieee;
use ieee.STD_logic_1164.all;
use ieee.STD_logic_unsigned.all;
entity clock0710 is -- divide50MHz to 1Hz
generic(d : integer :=50000000);
port( clk: in STD_logic;
dav: out STD_logic);
end;
architecture bhv of clock0710 is
signal s : STD_logic;
signal c :STD_logic_vector(25 downto 0);
begin
process(clk)
--variable cnt:STD_logic_vector(25 downto 0);
begin
if clk'event and clk='1'then
if c = (d-1) then
c <="00000000000000000000000000";s <= '1';
elsif c >= d/2then
c <= c+ 1;s <= '1';
else c <= c +1;s <= '0';
end if;
end if;
end process;
dav <= s;
end;
3.1.2计数模块
1. 设计原理
计数模块采用对1秒的信号源进行计数并向高位进位的思想实现计时功能,采用6个变量分别对时分秒的高低位进行计数,低位满后向高位进位。
2. 代码实现
时钟
library ieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entity hour0710 is
port(CLK,reset:instd_logic;
daout:out std_logic_vector(7 downto 0));
end entity hour0710;
architecture fun ofhour0710 is signal count:std_logic_vector(7 downto 0);
begin
daout<=count;
process(CLK,reset)
begin
IF(reset='0')THENcount<="00000000"; --若reset=0,则异步清零
elsif(CLK'event andCLK='1')then --否则,若clk上升沿到
if(count(3 downto0)="1001")then --若个位计时恰好到"1001"即9
if(count<16#23#)then --23进制
count<=count+7; --若到23D则
else
count<="00000000"; --复0
end if;
elsif(count<16#23#)then --若未到23D,则count进1
count<=count+1;
else --否则清零
count<="00000000";
end if; --end if(count(3downto 0)="1001")
end if; --end if(reset='0')
end process;
end fun;
分钟
library ieee;
use ieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entity minute0710 is
port(CLK,CLK1,reset,hour0710:instd_logic;
enhour0710:out std_logic;
daout:out std_logic_vector(7 downto 0));
end entity minute0710;
architecture fun ofminute0710 is
signal count:std_logic_vector(7downto 0);
signalenhour0710_1,enhour0710_2:std_logic;--enhour0710_1为59分时的进位信号
begin --enhour0710_2由clk调制后的手动调时脉冲信号串
daout<=count;
enhour0710_2<=(hour0710and CLK1); --enhour0710为手动调时控制信号,高电平有效
enhour0710<=(enhour0710_1or enhour0710_2);
process(CLK,reset,hour0710)
begin
if(reset='0')thencount<="00000000"; --若reset=0,则异步清零
elsif(CLK'event andCLK='1')then --否则,若clk上升沿到
if(count(3 downto0)="1001")then --若个位计时恰好到"1001"即9
if(count<16#60#)then --又若count小于 16#60#,即60
if(count="1011001")then --又若59D
enhour0710_1<='1'; --则置进位为1
count<="00000000"; --count复0
else
count<=count+7; --若count未到59D,则加7,即作"加6校正"
end if; --使前面的16#60#的个位转变为8421BCD的容量
elsecount<="00000000"; --count复0(有此句,则对无效状态电路可自启动)
end if; --end if(count<16#60#)
elsif(count<16#60#)then
count<=count+1; --若count<16#60#,则count加1
enhour0710_1<='0'after100 ns; --没有发生进位
elsecount<="00000000"; --否则,若count不小于16#60#,count复0
end if; --endif(count(3 downto 0)="1001")
end if; --endif(reset='0')
end process;
end fun;
秒钟
library ieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entity second0710 is
port(CLK,reset,min0710:std_logic;
enmin0710:out std_logic;
daout:out std_logic_vector(7 downto 0));
end entity second0710;
architecture fun ofsecond0710 is signal count:std_logic_vector(7 downto 0);
signal
enmin0710_1,enmin0710_2:std_logic;--enmin0710_1为59分时的进位信号
begin --enmi0710_2由clk调制后的手动调时脉冲信号串
daout<=count;
enmin0710_2<=(min0710and CLK); --enmin0710为手动调时控制信号,高电平有效
enmin0710<=(enmin0710_1or enmin0710_2);--enmin为向分进位信号
process(CLK,reset,min0710)
begin
if(reset='0')thencount<="00000000";--若reset=0,则异步清零
elsif(CLK'event andCLK='1')then --否则,若clk上升沿到
if(count(3 downto0)="1001")then --若个位计时恰好到"1001"即9
if(count<16#60#)then --又若count小于 16#60#,即60H
if(count="1011001")then --又若59D
enmin0710_1<='1';count<="00000000";--则置进位为1 count复0
else --未到59D
count<=count+7; --则加7,而+7=+1+6,即作"加6校正"
end if;
else --若count不小于16#60#
count<="00000000"; --count复0
end if; --end
elsif(count<16#60#)then --若个位计时未到"1001"则转此句再判
count<=count+1; --若count<16#60#,则count加1
enmin0710_1<='0'after100 ns; --没有发生进位
else --否则,若count不小于16#60#
count<="00000000"; --count复0
end if; --end if(count(3downto 0)="1001")
end if; --endif(reset='0')
end process;
end fun;
3.1.3 数码管显示模块
1. 设计原理
译码显示模块是将时间的数值转化成数码管段码值,计数器将分频器分频的信号计数后传给了译码器翻译成7位的信号传给晶体管。选六个晶体管来分别记录时分秒,分为两组数码管,所以分别定义高位和低位和来分别控制两组数码管。
2. 代码实现
分位
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity fenwei0710 is
port(uc:in std_logic_vector(7 downto 0);
dp1,dp2:out std_logic_vector(3 downto 0));
end;
architecture ott of fenwei0710 is
begin
process(uc)
begin
dp1(3 downto 0)<=uc(3 downto 0);
dp2(3 downto 0)<=uc(7 downto 4);
end process;
end;
译码器
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity LED7S is
Port(din: in std_logic_vector(3 downto 0);
y: out std_logic_vector(6 downto 0));
end LED7S;
architecture one of LED7S is
begin
process(din)
begin
case dinis
when "0000" =>y<="1000000"; ---Display "0"
when "0001" =>y<="1111001"; ---Display "1"
when "0010" =>y<="0100100"; ---Display "2"
when "0011" =>y<="0110000"; ---Display "3"
when "0100" =>y<="0011001"; ---Display "4"
when "0101" =>y<="0010010"; ---Display "5"
when "0110" =>y<="0000010"; ---Display "6"
when "0111" =>y<="1111000"; ---Display "7"
when "1000" =>y<="0000000"; ---Display "8"
when "1001" =>y<="0010000"; ---Display "9"
when "1010" =>y<="0001000"; ---Display "A"
when "1011" => y<="0000011"; --- Display "B"
when "1100" =>y<="1000110"; ---Display "C"
when "1101" =>y<="0100001"; ---Display "D"
when "1110" =>y<="0000110"; ---Display "E"
when "1111" =>y<="0001110"; ---Display "F"
when others => y<=null;
end case;
end process;
end one;
3.2 整体功能测试
整体顶层模块程序代码及原理图
-- Copyright (C)1991-2006 Altera Corporation
-- Your use ofAltera Corporation's design tools, logic functions
-- and othersoftware and tools, and its AMPP partner logic
-- functions, andany output files any of the foregoing
-- (includingdevice programming or simulation files), and any
-- associateddocumentation or information are expressly subject
-- to the termsand conditions of the Altera Program License
-- SubscriptionAgreement, Altera MegaCore Function License
-- Agreement, orother applicable license agreement, including,
-- withoutlimitation, that your use is for the sole purpose of
-- programminglogic devices manufactured by Altera and sold by
-- Altera or itsauthorized distributors. Please refer tothe
-- applicableagreement for further details.
-- PROGRAM"Quartus II"
-- VERSION"Version 5.1 Build 216 03/06/2006 Service Pack 2 SJ Full Version"
LIBRARY ieee;
USEieee.std_logic_1164.all;
LIBRARY work;
ENTITY Block1 IS
port
(
reset : IN STD_LOGIC;
min0710 : IN STD_LOGIC;
clk : IN STD_LOGIC;
hour0710 : IN STD_LOGIC;
enhour1 : OUT STD_LOGIC_VECTOR(6 downto 0);
enhour2 : OUT STD_LOGIC_VECTOR(6 downto 0);
enmin1 : OUT STD_LOGIC_VECTOR(6 downto 0);
enmin2 : OUT STD_LOGIC_VECTOR(6 downto 0);
ensecond1 : OUT STD_LOGIC_VECTOR(6 downto 0);
ensecond2 : OUT STD_LOGIC_VECTOR(6 downto 0)
);
END Block1;
ARCHITECTUREbdf_type OF Block1 IS
component clock
GENERIC ();
PORT(clk : IN STD_LOGIC;
dav : OUT STD_LOGIC
);
end component;
component led7s
PORT(din : IN STD_LOGIC_VECTOR(3 downto0);
y : OUT STD_LOGIC_VECTOR(6 downto 0)
);
end component;
componentfenwei0710
PORT(uc : IN STD_LOGIC_VECTOR(7 downto0);
dp1 : OUT STD_LOGIC_VECTOR(3 downto 0);
dp2 : OUT STD_LOGIC_VECTOR(3 downto 0)
);
end component;
componentminute0710
PORT(CLK : IN STD_LOGIC;
CLK1 : IN STD_LOGIC;
reset : IN STD_LOGIC;
hour0710 : IN STD_LOGIC;
enhour0710 : OUT STD_LOGIC;
daout : OUT STD_LOGIC_VECTOR(7 downto 0)
);
end component;
componentsecond0710
PORT(CLK : IN STD_LOGIC;
reset : IN STD_LOGIC;
min0710 : IN STD_LOGIC;
enmin0710 : OUT STD_LOGIC;
daout : OUT STD_LOGIC_VECTOR(7 downto 0)
);
end component;
component hour0710
PORT(CLK : IN STD_LOGIC;
reset : IN STD_LOGIC;
daout : OUT STD_LOGIC_VECTOR(7 downto 0)
);
end component;
signal SYNTHESIZED_WIRE_0 : STD_LOGIC_VECTOR(3 downto 0);
signal SYNTHESIZED_WIRE_1 : STD_LOGIC_VECTOR(7 downto 0);
signal SYNTHESIZED_WIRE_2 : STD_LOGIC_VECTOR(7 downto 0);
signal SYNTHESIZED_WIRE_3 : STD_LOGIC_VECTOR(3 downto 0);
signal SYNTHESIZED_WIRE_4 : STD_LOGIC_VECTOR(3 downto 0);
signal SYNTHESIZED_WIRE_5 : STD_LOGIC_VECTOR(3 downto 0);
signal SYNTHESIZED_WIRE_6 : STD_LOGIC_VECTOR(3 downto 0);
signal SYNTHESIZED_WIRE_7 : STD_LOGIC_VECTOR(3 downto 0);
signal SYNTHESIZED_WIRE_8 : STD_LOGIC;
signal SYNTHESIZED_WIRE_13 : STD_LOGIC;
signal SYNTHESIZED_WIRE_11 : STD_LOGIC_VECTOR(7 downto 0);
signal SYNTHESIZED_WIRE_12 : STD_LOGIC;
BEGIN
b2v_inst : clock
GENERIC MAP()
PORT MAP(clk =>clk,
dav => SYNTHESIZED_WIRE_13);
b2v_inst10 : led7s
PORT MAP(din =>SYNTHESIZED_WIRE_0,
y => ensecond1);
b2v_inst11 :fenwei0710
PORT MAP(uc =>SYNTHESIZED_WIRE_1,
dp1 => SYNTHESIZED_WIRE_4,
dp2 => SYNTHESIZED_WIRE_5);
b2v_inst12 :fenwei0710
PORT MAP(uc =>SYNTHESIZED_WIRE_2,
dp1 => SYNTHESIZED_WIRE_6,
dp2 => SYNTHESIZED_WIRE_7);
b2v_inst14 : led7s
PORT MAP(din =>SYNTHESIZED_WIRE_3,
y => ensecond2);
b2v_inst15 : led7s
PORT MAP(din =>SYNTHESIZED_WIRE_4,
y => enmin1);
b2v_inst18 : led7s
PORT MAP(din =>SYNTHESIZED_WIRE_5,
y => enmin2);
b2v_inst19 : led7s
PORT MAP(din =>SYNTHESIZED_WIRE_6,
y => enhour1);
b2v_inst20 : led7s
PORT MAP(din =>SYNTHESIZED_WIRE_7,
y => enhour2);
b2v_inst4 :minute0710
PORT MAP(CLK =>SYNTHESIZED_WIRE_8,
CLK1 => SYNTHESIZED_WIRE_13,
reset => reset,
hour0710 => hour0710,
enhour0710 => SYNTHESIZED_WIRE_12,
daout => SYNTHESIZED_WIRE_1);
b2v_inst6 :second0710
PORT MAP(CLK =>SYNTHESIZED_WIRE_13,
reset => reset,
min0710 => min0710,
enmin0710 => SYNTHESIZED_WIRE_8,
daout => SYNTHESIZED_WIRE_11);
b2v_inst8 :fenwei0710
PORT MAP(uc =>SYNTHESIZED_WIRE_11,
dp1 => SYNTHESIZED_WIRE_0,
dp2 => SYNTHESIZED_WIRE_3);
b2v_inst9 :hour0710
PORT MAP(CLK =>SYNTHESIZED_WIRE_12,
reset => reset,
daout => SYNTHESIZED_WIRE_2);
END;
实验箱调试结果
将程序下载到实验箱上,拨动开关SW2小时自动调节,拨动开关SW1分钟自动调节,按下开关SW0,所有时间会自动清零。
|