《EDA技术》
课程设计报告
题目: FPGA数字时钟设计
班级: 12电信本2
学号: 1203010211
姓名:高翔
同组人员:汤吉鑫王正提
指导教师:杨祖芳
2015年 5月1日
目录
1 设计任务 (1)
2 总体设计方案 (1)
2.1 设计思路 (1)
2.2 总体设计框图 (1)
3 单元电路设计 (1)
3.1 秒计数器模块设计与实现 (1)
3.2 分计数器模块设计与实现 (3)
3.3 时计数器模块设计与实现 (4)
3.4 校准模块 (5)
3.5 BCD七段显示译码器 (5)
3.6 3-8线译码器模块设计与实现 (6)
3.7 分频器的设计与实现 (7)
3.8 去抖模块 (7)
3.9 动态扫描数码显示器 (8)
3.10 顶层原理设计图 (8)
4 硬件测试与结果分析 (9)
4.1 硬件测试 (9)
4.2 测试过程及结果分析 (9)
5 收获与体会 (10)
参考书目 (10)
附录 (11)
1 设计任务
设计并实现具有一定功能的数字钟。包括清零、置数、计数、报时等功能。 (1)具有时、分、秒计数显示功能,且以24小时循环计时。 (2)具有清零的功能,且能够对计时系统的小时、分钟进行调整。 (3)具有整点报时功能。
2 总体设计方案
2.1 设计思路
本设计采用层次化设计方式,先设计数字时钟的底层器件:秒计数器、分
计数器、时计数器、bcd 七段显示译码器、3-8译码器、分频器、动态扫描数码显示器。顶层采用原理图设计方式,将所设计的底层器件连接起来构成一个具有计时和调时功能的数字时钟。 2.2 总体设计框图
图2-2 设计框图
3 单元电路设计
3.1 秒计数器模块设计与实现
计时模块使用的时钟信号为1Hz 。秒计时模块为60进制计数器,也可以看为个位为10进制十位为6进制。当秒的个位显示到9时,下一秒向十位进1
并将个位重新归零并开始计数,当十位为5个位为9时,计时器下一秒向分计数器进1并同时将秒计时器个位、十位归零。也可以看成计时器从00开始计数到59,当秒显示为59时,下一秒将显示00并从新开始计数,同时向分位为进1。当秒计时模块中扫描到有按键按下时,直接向分计时器进1,但不影响秒计时器的正常计数(扫描按键是
否按下的时钟速度要极快,否则可能无法扫描到是否有按键按下)。
3.1.1 秒计数器流程图如下:
Y
N
图3-1-1 秒钟计数器流程图
3.1.2 秒计数器生成模块如图所示:
图3-1-2 秒钟计数器模块图
其中,clk是时钟信号,daout是60计数输出,enmin是向分进位的高电平。
3.1.3 波形仿真图
图3-1-3 波形仿真图
波形分析:由波形图知秒计数器是由60进制计数器完成的00到59的循环计数功能,当计数到59时,再来一个计数脉冲则产生进位输出,即enmin=1,作为分计数器的计数脉冲。
秒脉冲
满60
向分进位
60计数器
清零
秒计数输出
3.2分计数器模块设计与实现
计时模块60进制计数器,也可以看为个位为10进制十位为6进制。分计时器接收到来自秒计时器的脉冲信号是,其个位自动进1,当分的个位显示到9时,下一秒向十位进1并将个位重新归零并开始计数,当十位为5个位为9时,计时器下一秒向时时器进1并同时将分计时器的个位、十位均归零。当分计时模块中扫描到有本模块的按键按下时,直接向时计时器进1,但不影响分计时器的正常计数。
3.2.1 分计数器流程图如下:
N
Y
Y
N
图3-2-1 分钟计数器流程图
3.2.2 分计数器生成模块如图所示:
图3-2-2 分钟计数器模块图
其中,clk是时钟信号,daout是60计数输出,enhour是向时进位的高电平。
3.2.3 波形仿真图
分计数输出向时进位
清零
60计数器
调分按键
按下
满60
进位高电平
图3-2-3 波形仿真图
波形分析:由波形图可知,该模块实现了分计数的功能,计数循环从00到59,计数脉冲为秒计数器的进位输出,即enmin。当计数到59时,再来一个计数脉冲则产生进位输出,即enhour=1,作为时计数器的计数脉冲。
3.3时计数器模块设计与实现
时计时器为一个24进制计数器,也可以看为个位由4进制、十位由2进制构成。当时计时器接收到来自分计时器的脉冲信号时,自动加1,当计数器为23时若再接收到一个脉冲信号则归零并重新开始计数。
3.3.1 时计数器流程图如下:
N
Y
Y
N
图3-3-1 时钟计数器流程图
3.3.2 时计数器生成模块如图所示:
图3-3-2 时钟计数器模块图
其中,clk是时钟信号,daout是24计数输出。
调时按键
按下
24计数器
满24
时计数输出
清零进位高电平
3.3.3 波形仿真图
图3-3-3 波形仿真图
波形分析:小时计数模块由24进制计数器完成的从00到23之间的循环计数,计数脉冲为分计数器的进位输出,即enhour。
3.4 校准模块
当开关拨至校时档时,电子钟秒计时工作,通过时、分校时开关分别对时、分进行校对,开关每按1次,与开关对应的时或分计数器加1,当调至需要的时与分时,拨动reset开关,电子钟从设置的时间开始往后计时。
3.5 BCD七段显示译码器
LED数码显示器是数字系统实验里面经常使用的一种显示器件,因为它经常显示的是十进制或十六进制的数,所以我们就要对实验里面所用到的二进制数进行译码,将它们转换成十进制的或是十六进制的数。此次实验使用的LED数码显示器是共阴的连接,高电平有效。输入信号为D0,D1,D2,D3,相应的输出8段为a、b、c、d、e、f、g、Dp。它们的关系表格如下:其中A,B,C,D 接拨号开关,a,b,c,d,e,f,g,dp和使能端AN(高电平工作)接数码显示接口,管脚映射均为I/O口,映射后,通过拨号开关改变输入二进制码,则输出数码管上显示相应的数值。
3-5-1 真值图
3-5-2 波形仿真图
3.6 3-8线译码器模块设计与实现
有驱动8位7段数码管共阴极扫描数码管的片选驱动信号和7段输出。位选模块产生3位的8位数码管的扫描信号和时钟显示数据,3位的数码管扫描信号通过3-8译码器转换成位选信号,时钟显示数据则是通过译码模块转变为0-9的数字显示。
3.6.1 3-8线译码器流程图如下:
图3-6-1 3-8线译码器流程图
3.6.2 3-8线译码器生成模块如图所示:
图3-6-2 3-8译码器模块图
其中,sel是时、分、秒选择信号,y是8位译码信号。
3.6.3 波形仿真图
图3-6-3 波形仿真图
波形分析:由波形图分析可知,3-8线译码器完成了3位信号的输入到8位译BCD码秒值
BCD码分值
BCD码时值
3-8线转换
数码管的2、
1位显示
数码管的5、
4位显示
数码管的8、
7位显示
码的输出功能。
3.7 分频器的设计与实现
3.7.1 分频器流程图如下:
由于要为秒计数器提供1hz的脉冲和数码显示提供1000hz的脉冲,所以要把50Mhz的时钟信号进行分频。
N Y N Y
这是产生1hz脉冲这是产生1000hz脉冲
3-7-1 分频器流程图
3.7.2 分频器生成模块如图所示:
3-7-2 分频器模块图
3.8 去抖模块
在计数模块钱加上去抖模块,去抖模块实际上就一个倒数计数器,主要目的是为了避免按键时按键的抖动效应使按键输入信号产生不必要的抖动,而造成重复统计按键次数造成错误的结果。因此,只需将按键输入信号作为计数器的重置输入,使计数器只有在按键时,且在输入信号为‘0’时间足够长的一次使重置无动作,而计数器开始倒数计数,自然课将输入信号在短时间内变为‘0’的情况滤掉。
50MHZ时钟
信号
二分频
次数加1
到达
25000000
次数变0
到达
25000
次数加1 次数变0
3-8-1 去抖模块图
3.9 动态扫描数码显示器
每个周期只选通一位数据。在周期1显示第一个数码,周期2显示第二个数码…在扫描4个阶段后,又重新按顺序循环。如果扫描的速度足够快,人感觉到就好像4个数码管同时显示。)
4位扫描数码显示器共有四组BCD码、4位输入线、8根8段译码输出线和4根位选通线。扫描工作中,先从四组BCD数据中选出一组,通过BCD/七段译码器译码后输出。与此同时,3/8 译码器产生位选通信号,则在此瞬间,显示器再改为显示要输出的数码。然后再选出下一组数据译码后输出,位选通信号则相应下移一位,将下一数码选通输出。
利用这个原理,利用VHDL语言编写实现6位动态数码的程序,可以将其分为两个模块:一个模块用来译码,一个模块是计数器(状态机)输出;编译成功后在实验箱上试验其功能的正确性。
3-9-1 波形仿真图
3.10 顶层原理设计图
将分频器、秒计数器、分计数器、时计数器、译码器、3-8线译码器按照要求连接起来就组成了整个数字时钟的原理图,如图所示。
3-10-1 顶层原理图
4 硬件测试与结果分析
4.1 硬件测试:
测试方式:clk选用clk1。KS[0]控制调分,KS[1]控制调时。数码管数码管8、7用作小时显示,高位是小时的十位,低位是小时的个位。数码管5、4用作分钟显示,高位是分钟的十位,低位是分钟的个位。数码管2、1用作秒钟显示,高位是秒钟的十位,低位是秒钟的个位。管脚分配如图所示。
4-1-1 引脚分配图
4.2 测试过程及结果分析
将文件下载到FPGA中,数码管上显示00-00-00,并开始计时,秒钟计到59向分钟进1,分钟计到59向小时进1。闭合KS[0]键分钟以1HZ的频率加1,加到59向小时进1,分钟清0。闭合KS[1]键小时以1HZ的频率加1,加到59小时清0。
本数字时钟能够满足正常计时和调分调时功能,达到预期的设计效果。
5 收获与体会
这次课程设计终于顺利完成了,在设计中遇到了很多问题,最后在老师的指导下,终于游逆而解。通过此次课程设计,使我更加扎实的掌握了有关EDA方面的知识,在设计过程中虽然遇到了一些问题,但经过一次又一次的思考,一遍又一遍的检查终于找出了原因所在,也暴露出了前期我在这方面的知识欠缺和经验不足。实践出真知,通过亲自动手制作,使我们掌握的知识不再是纸上谈兵。
这次课程设计让我进一步提高了用VHDL语言编程的能力。在实验的过程中在老师和同学的帮助下也弄懂数字钟一些功能原理,明白其工作状态。我认为,在这学期的实验中,不仅培养了独立思考、动手操作的能力,在各种其它能力上也都有了提高。更重要的是,在实验课上,我们学会了很多学习的方法。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正提高自己的实际动手能力和独立思考的能力。
6指导老师意见
参考书目
[1] 孙志雄、谢海霞、杨伟、郑心武,《EDA技术与应用》,北京,机械工业出版社,2013年
[2] 谭会生、张昌凡,《EDA技术及应用(第三版)》,西安,西安电子科技大学出版社,2013年
附录:
程序代码
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY yimaqi IS
PORT ( din : IN STD_LOGIC_VECTOR(0 TO 2);
output : OUT STD_LOGIC_VECTOR(0 TO 7)); END yimaqi;
ARCHITECTURE behav OF yimaqi IS
SIGNAL SINT : STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
PROCESS(din)
BEGIN
IF (din="000") THEN output <="10000000";
ELSIF (din="001") THEN output <="01000000";
ELSIF (din="010") THEN output <="00100000";
ELSIF (din="011") THEN output <="00010000";
ELSIF (din="100") THEN output <="00001000";
ELSIF (din="101") THEN output <="00000100";
ELSIF (din="110") THEN output <="00000010";
ELSE output <="00000001";
END IF;
END PROCESS;
END behav;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY BCD IS
PORT(BCD_CODE: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
AN: IN STD_LOGIC;
BCD_OUT: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
end BCD;
ARCHITECTURE hehav OF BCD IS
BEGIN
PROCESS(AN,BCD_CODE)
BEGIN
IF(AN='1') THEN
CASE BCD_CODE IS
when "0000" => BCD_OUT<="11111100";
when "0001" => BCD_OUT<="01100000";
when "0010" => BCD_OUT<="11011010";
when "0011" => BCD_OUT<="11110010";
when "0100" => BCD_OUT<="01100110";
when "0101" => BCD_OUT<="10110110";
when "0110" => BCD_OUT<="10111110";
when "0111" => BCD_OUT<="11100000";
when "1000" => BCD_OUT<="11111110";
when "1001" => BCD_OUT<="11110110";
when "1010" => BCD_OUT<="11101110";
when "1011" => BCD_OUT<="00111110";
when "1100" => BCD_OUT<="10011100";
when "1101" => BCD_OUT<="01111010";
when "1110" => BCD_OUT<="10011110";
when "1111" => BCD_OUT<="10001110";
when others=> BCD_OUT<="00000000";
END CASE;
ELSE
BCD_OUT<="ZZZZZZZZ";
END IF;
END PROCESS;
END hehav;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY F_DIVIDER IS
GENERIC(N: INTEGER:=10;
N1: INTEGER:=11);
PORT(
CLK: IN STD_LOGIC;
CLK10: OUT STD_LOGIC;
CLK11: OUT STD_LOGIC;
CLK2: OUT STD_LOGIC
);
END F_DIVIDER;
ARCHITECTURE BEHAV OF F_DIVIDER IS
SIGNAL DATA:INTEGER RANGE 0 TO 10;
SIGNAL CNT: STD_LOGIC_VECTOR(N-1 DOWNTO 0); SIGNAL CNT1: STD_LOGIC_VECTOR(N1-1 DOWNTO 0); SIGNAL Q:STD_LOGIC;
BEGIN
P1: PROCESS(CLK)
BEGIN
IF(CLK'EVENT AND CLK='1') THEN
CNT <= CNT+1;
END IF;
END PROCESS P1;
CLK10 <= CNT(N-1);
P2: PROCESS(CLK)
BEGIN
IF(CLK'EVENT AND CLK='1') THEN
CNT1 <= CNT1+1;
END IF;
END PROCESS P2;
CLK11 <= CNT1(N1-1);
P3: PROCESS(CLK)
BEGIN
IF(CLK'EVENT AND CLK='1') THEN
IF(DATA=0) THEN
DATA<=0;
Q<=NOT Q;
ELSE
DATA<=DATA+1;
END IF;
END IF;
END PROCESS P3;
CLK2 <= Q;
END BEHAV;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY LED IS
PORT ( CLK: IN STD_LOGIC;
SG: OUT STD_LOGIC_VECTOR(6 DOWNTO 0); BT:OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
A:BUFFER STD_LOGIC_VECTOR(2 DOWNTO 0)); END LED;
ARCHITECTURE rt OF LED IS
BEGIN
P1:PROCESS(CLK)
BEGIN
IF CLK'EVENT AND CLK='1' THEN
IF A="101" THEN A<="000";
ELSE A<=A+1;END IF;
END IF;
END PROCESS P1;
P2:PROCESS(A)
BEGIN
CASE A IS
WHEN "000" =>BT<="000";SG<="1011111";
WHEN "001"=>BT<="001";SG<="1011011";
WHEN "010" =>BT<="010";SG<="0110011";
WHEN "011"=>BT<="011";SG<="1111001";
WHEN "100" =>BT<="100";SG<="1101101";
WHEN "101" =>BT<="101";SG<="0110000";
WHEN OTHERS =>SG<="XXXXXXX" ;
END CASE;
END PROCESS P2;
END rt;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity clock is
port(clk:in std_logic;--12M时钟
keyin:in std_logic;
speak:out std_logic;--蜂鸣器
dout:out std_logic_vector(7 downto 0);--段码
selout:out std_logic_vector(2 downto 0));--位选end clock;
architecture one of clock is
signal count:integer range 0 to 11999999;--1HZ秒信号
signal counf:integer range 0 to 11999;--1000HZ
SIGNAL CP_5ms : STD_LOGIC;
SIGNAL Q1,Q2,Q3: STD_LOGIC;
SIGNAL keyout : STD_LOGIC;
SIGNAL CJ:STD_LOGIC_VECTOR(2 DOWNTO 0);
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 sec1:std_logic_vector(3 downto 0);--秒的十位
signal sec2: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 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 clk1,clkk,beep:std_logic;
begin
------------------------------------------------分频
fp:process(clk)
begin
if rising_edge(clk) then
count<=count+1;
counf<=counf+1;
if count=11999999 then clk1<='1';---1Hz
count<=0;
beep<='1';
elsif count>5999999 then beep<='0'; ---2Hz
else clk1<='0';
end if;
if counf=11999 then clkk<='1';--1000HZ
counf<=0;
else clkk<='0';
end if;
end if;
end process fp;
----------------------------------------------位扫描choice:process(clkk)---位选扫描
begin
if rising_edge(clkk)then
if sel="111" then
sel<="000";
else
sel<=sel+1;
end if;
end if;
end process choice;
--------------------------------------------秒个位
s220:process(clk1,cj)
begin
if clk1'event and clk1='1' then
if sec2="1001" then ---其中sec2是秒的个位 sec2<="0000";
elsif cj="010" then
sec2<=sec2;
else sec2<=sec2+1;
end if;
end if;
if cj="001" then sec2<="0000"; ---秒个位复位
end if;
end process s220;
---------------------------------------------秒十位
s110:process(clk1,cj)
begin
if clk1'event and clk1='1' then
if (sec1="0101" and sec2="1001")then---其中sec1是秒钟的十位
sec1<="0000";
elsif cj="010" then
sec1<=sec1;
else if sec2="1001"then
sec1<=sec1+1;
end if;
end if;
end if;
if cj="001" then sec1<="0000"; ---秒十位复位
end if;
end process s110;
----------------------------------------------分钟个位
m220:process(clk1,sec1,sec2,cj)
begin
if clk1'event and clk1='1' then
if min2="1001"and (sec1="0101" and sec2="1001")then----其中min2是分钟的个位
min2<="0000";
elsif min2="1001"and (cj="011" and cj="100")then---