设计题目: 基于VHDL电子钟的设计
一、概述…………………………………………………………3
1.1目的……………………………………………………………3
1.2课程设计的要求和功能………………………………………3
二、总结…………………………………………………………..3
2.1课程设计进行过程及步骤……………………………………3
2.2所遇到的问题,如何解决问题……………………………….15
2.3体会收获以及建议…………………………………………….15
3.4参考资料(书,网络资料)………………………………….15
三、教师评语………………………………………………………16
四、成绩……………………………………………………………16
一、概述
1.1目的
1. 基于CPLD系统模块板,设计一个电子钟。来熟悉CPLD的工作原理以及对VHDL的使用。
2. 通过设计出一个电子钟具有校时功能,来巩固分频,键盘扫描,计数,动态扫描等知识内容。
1.2课程设计的要求和功能
设计一个电子钟,能进行正常的时分秒计时功能,分别有六个数码管显示24小时,60分钟,60秒的计数器显示。
利用实验箱系统上的按键实现“校时”、“校分”功能:
(1)按下“SA”键时,计时器快速递增,按24小时循环,进行时校正;
(2)按下“SB”键时,计分器快速递增,按60分循环,进行分校正
(3)按下“SC”键时,秒清零,进行秒校正;
二、总结
2.1课程设计进行及步骤
1.设计提示
系统框图见下
2.系统结构设计描述
(1)系统顶层文件
1.顶层原理图见下
2.各个模块的解释
(1)五个输入量clk50MHz,SA,SB,SC,reset:
其中clk50MHz为总体系统提供时钟,并且经过分频来分别对电子钟模块提供时钟,产生一秒一秒的进位信号,对显示模块的计数器提供时钟实现显示模块的扫描功能,对按键去抖动提供时钟,实现键盘扫描的功能。SA,SB,SC用来控制按键,实现按键控制,SA是实现“时”加一,SB是实现“分”加一,SC是实现“秒”清零。Reset是来控制按键功能的使能。
(2)按键功能模块
三个输入chos ,date0,date1的功能是:chos接受来自按键的信号,若按键按下,则将date0的内容,也就是通过按键产生的脉冲来控制电子钟进行加一,若按键没有按下,则将“秒”分频信号接入电子钟的clk计数输入端,通过时钟脉冲来控制电子钟。
(3)电子钟计数模块
有5个输入ci,nreset,load,clk,d[7..0],作用分别是ci是使能端,直接接高电位,nreset是复位,load和d[7..0]是用来置数的,clk提供计数时钟,也就是一秒一个脉冲。
输出端有三个,co是进位功能,只有“秒”和“分”模块有效,qh[3..0],ql[3..0]是分位的数字输出端,一个是十位,一个是个位。
(4)显示模块
输入端有qcnt接受来自计数器的计数实现显示扫描,d0h,d1h,d0m,d1m,d0s,d1s分别是接收的来自“秒”“分”“时”个位十位的数据,seg输出LCD的段扫描结果,SCAN输出LCD位扫描结果。
(2)系统各个模块的VHDL程序
1.显示模块
Library ieee;
Use ieee.std_logic_11.all;
Use ieee.std_logic_unsigned.all;
Use ieee.std_logic_arith.all;
entity display is
port(
qcnt: IN integer range 0 to 7; --计数值输入
d0h,d1h,d0m,d1m,d0s,d1s : IN integer range 0 to 9;
--分位得到的十位数和个位数
seg: OUT std_logic_vector(6 downto 0); --7位段码输出
scan: OUT std_logic_vector(7 downto 0) --8为位码输出
);
end display;
architecture a of display is
signal data: integer range 0 to 10;
begin
process(qcnt,d0h,d1h,d0m,d1m,d0s,d1s)
begin
case qcnt is
when 0 => scan <= "11111110"; data <= d0h;
when 1 => scan <= "11111101"; data <= d1h;
when 2 => scan <= "11111011"; data<= 10;
when 3 => scan <= "11110111"; data <= d0m;
when 4 => scan <= "11101111"; data <= d1m;
when 5 => scan <= "11011111"; data<= 10;
when 6 => scan <= "10111111"; data <= d0s;
when others => scan <= "01111111"; data <= d1s;
end case;
end process;
process(data)
begin
case data is
when 0 => seg <= "0111111"; --0
when 1 => seg <= "0000110"; --1
when 2 => seg <= "1011011"; --2
when 3 => seg <= "1001111"; --3
when 4 => seg <= "1100110"; --4
when 5 => seg <= "1101101"; --5
when 6 => seg <= "1111101"; --6
when 7 => seg <= "0000111"; --7
when 8 => seg <= "1111111"; --8
when 9 => seg <= "1100111"; --9
when 10 => seg <="1000000"; --
when others => seg <= "0000000";
end case;
end process;
end a;
动态显示计数器部分:
LIBRARY ieee;
USE ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
-- Entity Declaration
ENTITY qcnt_display IS
-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
PORT
(
clk : IN STD_LOGIC;
qcnt : buffer STD_LOGIC_VECTOR(2 downto 0)
);
-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
END qcnt_display ;
-- Architecture Body
ARCHITECTURE cnt_architecture OF qcnt_display IS
BEGIN
PROCESS (clk)
BEGIN
IF (clk'EVENT AND clk = '1') THEN
qcnt <= qcnt+1;
END IF;
END PROCESS;
END cnt_architecture;
2. 分位计数模块
“秒”,“分”部分:
LIBRARY ieee;
USE ieee.std_logic_11.all;
USE ieee.std_logic_unsigned.all;
-- Entity Declaration
ENTITY counter60 IS
END counter60;
-- Architecture Body
ARCHITECTURE counter_architecture OF counter60 IS
BEGIN
co<='1' when ( qh ="0101" and ql ="1001" and ci ='1') else '0';
process (clk,nreset)
end if;
END counter_architecture;
“时”部分:
LIBRARY ieee;
USE ieee.std_logic_11.all;
USE ieee.std_logic_unsigned.all;
-- Entity Declaration
ENTITY counter24 IS
-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
PORT
(
ci: in std_logic;
nreset : IN STD_LOGIC:='1';
load: IN STD_LOGIC;
clk : IN STD_LOGIC;
d :in std_logic_vector(7 downto 0);
co: out std_logic:='0';
qh: buffer std_logic_vector(3 downto 0);
ql : buffer std_logic_vector(3 downto 0)
);
-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
END counter24;
-- Architecture Body
ARCHITECTURE counter_architecture OF counter24 IS
BEGIN
--co<='1' when ( qh ="0010" and ql ="0011" and ci ='1') else '0';
process (clk,nreset)
begin
--if (nreset='0') then
--qh <="0000";
-- ql <="0000";
if rising_edge(clk) then
if (load ='1') then
qh<= d(7 downto 4);
ql<= d(3 downto 0);
elsif(ci='1') then
if(qh=0 or qh=1) then
if(ql=9) then
ql<="0000";
if(qh=2) then
qh<="0000";
else
qh<=qh+1;
end if;
else
ql<=ql+1;
end if;
else
if(ql=3) then
ql<="0000";
if(qh=2) then
qh<="0000";
else
qh<=qh+1;
end if;
else
ql<=ql+1;
end if;
end if;
end if;
end if;
end process;
END counter_architecture;
3. 分频模块
Library ieee;
Use ieee.std_logic_11.all;
Use ieee.std_logic_unsigned.all;
Use ieee.std_logic_arith.all;
Entity fdiv_duo is
port(
clkin: IN std_logic;
clkout_200HZ: buffer std_logic;--键盘去抖动
clkout_1KHZ : buffer std_logic;--显示模块计数器
clkout_10HZ : buffer std_logic;--按键选择
clkout_1HZ : buffer std_logic --计数器模块
);
End fdiv_duo;
Architecture a of fdiv_duo is
signal cnt_1HZ : natural range 0 to 24999999 ;
signal cnt_10HZ : natural range 0 to 249999999;
signal cnt_1KHZ : natural range 0 to 24999;
signal cnt_200HZ : natural range 0 to 124999;
Begin
process(clkin)
begin
if(clkin'event and clkin='1') then
if cnt_1HZ=24999999 then
cnt_1HZ<= 0;
clkout_1HZ<= not clkout_1HZ;
else
cnt_1HZ<= cnt_1HZ + 1;
end if;
if cnt_10HZ=249999999 then
cnt_10HZ <= 0;
clkout_10HZ <= not clkout_10HZ;
else
cnt_10HZ <= cnt_10HZ + 1;
end if;
if cnt_1KHZ=24999 then
cnt_1KHZ<= 0;
clkout_1KHZ <=not clkout_1KHZ;
else
cnt_1KHZ <=cnt_1KHZ + 1;
end if;
if cnt_200HZ=124999 then
cnt_200HZ <= 0;
clkout_200HZ<= not clkout_200HZ;
else
cnt_200HZ <= cnt_200HZ + 1;
end if;
end if;
end process;
End a;
4. 键盘控制模块
时钟和分钟的键盘去抖动和“增益”,“清零”控制部分:
Library ieee;
Use ieee.std_logic_11.all;
Use ieee.std_logic_unsigned.all;
Use ieee.std_logic_arith.all;
Entity debounce is
port(
clk200hz ,reset : IN std_logic; --200HZ时钟
din : IN std_logic;
dout : OUT std_logic);
End debounce;
architecture a of debounce is
type state is (S0, S1, S2);--定义状态机类型
signal current : state;
begin
process (clk200hz,reset,din)
begin
if(reset='1') then --状态机复位 dout输出信号复位
current<=S0;
dout<='1';
elsif(clk200hz'event and clk200hz='1') then
case current is
when S0=>
dout<='1';
if(din='0') then
current<=S1;
else
current<=S0;
end if;
when S1=>
dout<='1';
if(din='0')then
current<=S2;
else
current<=S0;
end if;
when S2=>
dout<='0';
if(din='0') then
current<=S2;
else
current<=S0;
end if;
when others=>
dout<='1';
current<=S0;
end case;
end if;
end process;
end a;
作用解释:当检测到按键被按下时,将按键的输出直接给计数模块的时钟控制通过按键控制计数时钟从而实现“增益”功能,如果没有检测到有效按键,“时”和“分”计数模块就受进位信号的控制。
library ieee;
use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
entity choose is
port
(chos: in std_logic;
date0,date1:in std_logic;
dout:out std_logic);
end choose;
architecture behave of choose is
begin
with chos select
dout <=date0 when '0',
date1 when others;
end behave;
“清零”功能的实现利用按键信号去控制“秒”模块的“复位”。
(3)实验效果图
22-01-27时按下秒钟清零
继续按分钟增益按钮,使分钟从1加到9
然后按时钟增益,使时钟从22加到下一轮的9时
2.2所遇到的问题,如何解决问题
(1)在分频时,如果键盘去抖动频率设计不合适会造成按键不灵敏,如果显示部分频率设置不好也会造成显示时音频率过快数字不清楚。
解决办法:虽然实现分频的程序很多,但是有些程序的分频效果并不是很好,我这里用的是偶数分频器的第二种方法(取反或加一
(2)在设计时分秒的模模块时,因为我采用的是BCD计数器,所以在实现“分秒”的60进位比较容易,但是在实现“24小时”要注意,不然很容易出现时位为“1,2,3,11,12,13”的变化。
解决办法:
设计一个进位清零判断,是个位到了9需要清零还是到了3需要清零,取决于十位0和1还是2.
2.3体会收获以及建议
通过设计电子钟,重温了动态显示的设计、模计数器的设计以及按键去抖动设计,这里面主要的部分在于对电子钟按键控制,通过设计一个模块来判断按键是否有效后利用进位变量去触发计数器实现增益功能,或者利用判断按键是否有效将模计数器结果清零来实现置零功能。
在设计中,有很多细节问题会决定实验效果,所以一定要认真,多思考,并且要善于和同学交流讨论,可能自己在设计时会遇到盲区,需要别的同学的指点,比如我在设计按键功能判断时就向夏良飞同学请教了他的设计思路,然后再根据自己的理解设计出来选择器来实现按键控制功能。
3.4参考资料(书,网络资料)
《现在电子系统设计》
三、教师评语
四、成绩