Download presentation
Presentation is loading. Please wait.
1
第7章 VHDL设计应用实例 7.1 8位加法器的设计 7.2 分频电路 7.3 数字秒表的设计
2
7.1 8位加法器的设计 1.设计思路 加法器是数字系统中的基本逻辑器件,减法器和硬件乘法器都可由加法器来构成。多位加法器的构成有两种方式:并行进位和串行进位。并行进位加法器设有进位产生逻辑,运算速度较快;串行进位方式是将全加器级联构成多位加法器。
3
并行进位加法器通常比串行级联加法器占用更多的资源。随着位数的增加,相同位数的并行加法器与串行加法器的资源占用差距也越来越大。因此,在工程中使用加法器时,要在速度和容量之间寻找平衡点。
实践证明,4位二进制并行加法器和串行级联加法器占用几乎相同的资源。这样,多位加法器由4位二进制并行加法器级联构成是较好的折中选择。本设计中的8位二进制并行加法器即是由两个4位二进制并行加法器级联而成的,其电路原理图如图7.2所示。
4
图7.2 8位加法器电路原理图
5
2.VHDL源程序 1) 4位二进制并行加法器的源程序ADDER4B.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY ADDER4B IS 位二进制并行加法器 PORT(C4: IN STD_LOGIC; 低位来的进位
6
A4: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --4位加数
B4: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --4位被加数 S4: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--4位和 CO4: OUT STD_LOGIC); 进位输出 END ENTITY ADDER4B; ARCHITECTURE ART OF ADDER4B IS SIGNAL S5:STD_LOGIC_VECTOR(4 DOWNTO 0); SIGNAL A5,B5: STD_LOGIC_VECTOR(4 DOWNTO 0);
7
BEGIN A5<='0'& A4; --将4位加数矢量扩为5位,为进位提供空间 B5<='0'& B4; --将4位被加数矢量扩为5位,为进位提供空间 S5<=A5+B5+C4 ; S4<=S5(3 DOWNTO 0); CO4<=S5(4); END ARCHITECTURE ART;
8
2) 8位二进制加法器的源程序ADDER8B.VHD
LIBRARY IEEE; USE IEEE.STE_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL: ENTITY ADDER8B IS --由4位二进制并行加法器级联而成的8位二进制加法器 PORT(C8:IN STD_LOGIC; A8:IN STD_LOGIC_VECTOR(7 DOWNTO 0); B8:IN STD_LOGIC_VECTOR(7 DOWNTO 0);
9
S8:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
CO8:OUT STD_LOGIC); END ENTITY ADDER8B; ARCHITECTURE ART OF ADDER8B IS COMPONENT ADDER4B IS --对要调用的元件ADDER4B的界面端口进行定义 PORT(C4:IN STD_LOGIC; A4:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
10
B4:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
S4:OUT STD_LOGIC_VECTOR(3 DOWNTO 0); CO4:OUT STD_LOGIC); END COMPONENT ADDER4B; SIGNAL SC:STD_LOGIC; 位加法器的进位标志 BEGIN U1:ADDER4B --例化(安装)一个4位二进制加法器U1 PORT MAP(C4=>C8,A4=>A8(3 DOWNTO 0),B4=>B8(3 DOWNTO0),
11
S4=>S8(3 DOWNTO 0),CO4=>SC);
U2:ADDER4B --例化(安装)一个4位二进制加法器U2 PORT MAP(C4=>SC,A4=>A8(7 DOWNTO 4),B4=>B8(7 DOWNTO 4), S4=>S8 (7 DOWNTO 4),CO4=>CO8); END ARCHITECTURE ART;
12
7.2 分频电路 例1:2分频、4分频、8分频、16分频
14
例1:2分频、4分频、8分频、16分频 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY clk_div IS PORT(clk :IN STD_LOGIC; clk_div2 :OUT STD_LOGIC; clk_div4 :OUT STD_LOGIC; clk_div8 :OUT STD_LOGIC; clk_div16 :OUT STD_LOGIC); END clk_div;
15
ARCHITECTURE rtl OF clk_div6 IS
SIGNAL count :STD_LOGIC_VECTOR(3 DOWNTO 0); BEGIN PROCESS(clk) IF (clk’EVENT AND clk =’1’) THEN IF (count = “1111”) THEN Count <= (OTHERS=>’0’); ELSE Count := count+1 ; END IF; END PROCESS; Clk_div2 <= count(0); Clk_div4 <= count(1); Clk_div8 <= count(2); Clk_div16 <= count(3); END rtl;
16
例2:6分频的分频电路 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY clk_div6 IS PORT(clk :IN STD_LOGIC; clk_out :OUT STD_LOGIC); END clk_div6; ARCHITECTURE rtl OF clk_div6 IS SIGNAL clk_temp :STD_LOGIC; BEGIN
17
PROCESS(clk) VARIABLE counter: INTEGER RANGER 0 TO 15; CONSTANT md: INTEGER :=3; BEGIN IF (clk’EVENT AND clk =’1’) THEN IF (counter = md) THEN Counter := 0; Clk_temp <= NOT clk_temp; ELSE Counter := counter +1 ; END IF; END PROCESS; Clk_out <= clk_temp; END rtl;
18
例2实现了一个6分频的分频电路,并且输出信号的占空比为1:1。
若需要得到的占空比不是1:1的分频电路,应如何设计分频电路? 方法是: 首先描述一个计数器电路,然后根据计数电路的并行输出信号来决定输出时钟信号的高低电平,即可完成这种分频电路的VHDL语言描述。 例3所示是一个16分频电路,并且分频后时钟信号的占空比为1:15,描述该分频电路功能的VHDL语言程序如下:
19
例3: 16分频电路,分频后时钟信号的占空比为1:15
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY clk_div16 IS PORT(clk :IN STD_LOGIC; clk_out :OUT STD_LOGIC); END clk_div16; ARCHITECTURE rtl OF clk_div16 IS SIGNAL counter :STD_LOGIC; BEGIN
20
P1: PROCESS(clk) BEGIN IF (clk’EVENT AND clk =’1’) THEN IF (counter =”1111”) THEN Counter <= (OTHERS=>’0’); ELSE Counter := counter +1 ; END IF; END PROCESS;
21
P2: PROCESS(clk) BEGIN IF (clk’EVENT AND clk =’1’) THEN IF (counter =”1111”) THEN Clk_out < = ‘1’; ELSE Clk_out <= ‘0’ ; END IF; END PROCESS; END rtl; 思考:用此程序实现占空比为1:1的分频电路,在哪进行修改?
22
Clk clk_out 10分频电路 U0 20分频电路 U1 200分频电路
23
首先实现10分频电路和20分频电路的VHDL语言描述。
24
7.3 1秒计时电路的设计 外部输入的频率为1KHz,要求产生一个1S的时钟信号 1Kz ( 1/1000 秒) 10分频 (1/100秒) 10分频 (1/10秒) 10分频 1秒 clk001 10 分 频 10 分 频 clk01 10 分 频 CLK(1KHz) clk1s
25
(1)10分频的VHDL语言描述 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY clk_div10 IS PORT(clk :IN STD_LOGIC; clk_out :OUT STD_LOGIC); END clk_div10;
26
ARCHITECTURE rtl OF clk_div10 IS
SIGNAL clk_temp :STD_LOGIC; BEGIN PROCESS(clk) VARIABLE counter: INTEGER RANGER 0 TO 15; IF (clk’EVENT AND clk =’1’) THEN IF (counter = 9) THEN Counter := 0; Clk_out <= ‘1’; ELSE Counter :=counter +1 ; Clk_out <= ‘0’; END IF; END PROCESS; END rtl;
27
(2)1s计时电路的VHDL语言描述 Library ieee; Use ieee.std_logic_1164.all; Entity t1sec is port(clk1khz:in std_logic; clk1s:out std_logic); End t1sec; Architecture rtl of t1sec is signal clk001,clk01:std_logic; begin u0:clk_div10 port map(clk1khz,clk001); u1:clk_div10 port map(clk001,clk01); u2:clk_div10 port map(clk01,clk1s); End rtl;
28
交通十字路口的红绿信号灯按如下规律控制: 南北方向通行绿灯亮30秒后,禁止通行红灯亮30秒。
例: 交通十字路口的红绿信号灯按如下规律控制: 南北方向通行绿灯亮30秒后,禁止通行红灯亮30秒。 东西方向通行绿灯亮30秒后,禁止通行红灯亮30秒。如此循环交替通行。红绿灯用红绿色发光二极管模拟,如图所示: 红 绿 南北向 东西向 控 制 逻 辑 绿 1KHz时钟
29
已知时钟输入Clk频率为1KHz,试画出控制逻辑框图,并采用VHDL语言描述该控制逻辑。(10分频器和3分频器已生成,可直接使用)。
Component cnt10 Port(reset,clk:in std_logic; Carry:out std_logic); End component Component cnt3 Port(reset,clk:in std_logic; Carry:out std_logic); End component
30
7.3 数字秒表的设计 1.设计要求(秒表的功能描述)
7.3 数字秒表的设计 1.设计要求(秒表的功能描述) (1)要求设置复位开关。当按下复位开关时,秒表清零并做好计时准备。在任何情况下只要按下复位开关,秒表都要无条件地进行复位操作,即使是在计时过程中也要无条件地进行清零操作。 (2)要求设置启/停开关。当按下启/停开关后,将启动秒表并开始计时,当再按一下启/停开关时,将终止秒表的计时操作。 (3)要求计时精确度大于0.01秒。要求设计的计时器能够显示分(2位)、秒(2位)、0.1秒(1位)的时间。 (4)要求秒表的最长计时时间为1小时。
31
输入信号 复位开关信号reset_sw 启/停开关信号start_on_off 系统电源复位信号sysreset 外部时钟信号clk 输出信号 分十位LED七段显示数码管输出信号min10seg(6 downto 0) 分个位LED七段显示数码管输出信号minseg(6 downto 0) 秒十位LED七段显示数码管输出信号sec10seg(6 downto 0) 秒个位LED七段显示数码管输出信号secseg(6 downto 0) 0.1秒位LED七段显示数码管输出信号sec01seg(6 downto 0)
32
STOPWATCH 7 Reset_sw Start_on_off sysreset clk Min10seg[6..0]
sec10seg[6..0] sysreset secseg[6..0] clk sec01seg[6..0]
33
秒表系统共分成5个模块: 键输入模块、 时钟分频模块、 控制模块、 秒表计时模块 显示模块。
34
键输入模块 输入信号: 复位开关信号reset_sw; 启/停开关信号start_on_off; 外部时钟信号clk;
输出信号; 去除抖动后的复位信号reset; 去除抖动后的启/停信号on_off;
35
时钟分频模块 输入信号: 外部时钟信号clk; 输出信号: 用来消除抖动的时钟信号clk1; 秒表的内部计时时钟信号clk0;
36
控制模块 输入信号: 去除抖动后的复位信号reset; 去除抖动后的启/停信号on_off; 秒表的内部计时时钟信号clk0 输出信号:
秒表定时计数的使能信号enable;
37
秒表计时模块 输入信号: 去除抖动后的复位信号reset0; 秒表的内部计时时钟信号clk0; 秒表定时计数的使能信号enable;
输出信号: 分十位信号min10; 分个位信号min; 秒十位信号sec10; 秒个位信号sec; 0.1秒位信号sec01;
38
秒表显示模块 输入信号: 外部时钟信号clk; 分十位信号min10; 分个位信号min; 秒十位信号sec10; 秒个位信号sec;
输出信号: 分十位信号七段显示数码管的输出信号min10seg; 分个位信号七段显示数码管的输出信号minseg; 秒十位信号七段显示数码管的输出信号sec10seg; 秒个位信号七段显示数码管的输出信号secseg; 0.1秒位信号七段显示数码管的输出信号sec01seg;
39
7.4 闹钟系统的设计 闹钟系统的设计要求及设计思路 要求设计一个带闹钟功能的24小时计时器,计时器的外观如图6.14所示。
40
图6.14 计时器外观
41
该计时器设计要求完成如下功能: (1) 计时功能:这是本计时器设计的基本功能,每隔一分钟计时一次,并在显示屏上显示当前时间。 (2) 闹钟功能:如果当前时间与设置的闹钟时间相同,则扬声器发出蜂鸣声。 (3) 设置新的计时器时间:用户用数字键‘0’~‘9’输入新的时间,然后按 "TIME"键确认。
42
(4) 设置新的闹钟时间:用户用数字键“0”~“9”输入新的时间,然后按“ALARM”键确认。过程与(3)类似。
43
闹钟系统的控制器的设计 1.设计思路 控制器命名为ALARM_CONTROLLER,其外部端口如图6.15所示。各端口的作用如下:
44
图6.15 控制器的外部端口
45
(1) CLK为外部时钟信号,RESET为复位信号。
(2) 当KEY为高电平(KEY= '1')时,表示用户按下数字键(“0”~“9”)。 (3) 当ALARM_BUTTON为高电平时,表示用户按下“ALARM”键。 (4) 当TIME_BUTTON为高电平时,表示用户按下“TIME”键。 (5) 当LOAD_NEW_A为高电平时,控制(闹钟时间寄存器)加载新的闹钟时间值。
46
(6) 当LOAD_NEW_C为高电平时,控制(时钟计数器)设置新的时间值。
(7) 当SHOW_NEW_TIME为高电平时,控制(七段数码显示电路)显示新的时间值,即用户通过数字键输入的时间;否则,当SHOW_NEW_TIME为低电平时,根据SHOW_A信号的值控制显示当前时间或闹钟时间。
47
根据设计要求及端口设置,需要五个状态来实现:
S0:表示电路初态即正常时钟计数状态,完成前面设计功能 (1) 的工作。 S1:接收键盘输入状态。在状态S0时用户按下数字键后进入此状态。在此状态下,显示屏上显示的是用户键入的数字。
48
S2:设置新的闹钟时间。在状态S1时用户按下ALARM键后进入此状态。
S3:设置新的计时器时间。在状态S1时用户按下TIME键后进入此状态。 S4:显示闹钟时间。在状态S0时用户直接按下ALARM键后进入此状态。
49
在此状态下,显示屏上显示的是所设置的闹钟时间。注意:在此状态下,用户按下ALARM键后,显示屏上保持显示闹钟时间,经过一段时间以后,再返回状态S0显示计时器时间。相应的状态转换及控制如表6.1所示。
50
表6.1 控制器状态转换及控制输出表
51
表6.1中没有显式说明的控制信号赋值,表示信号的值为 零。例如在状态S0,当信号KEY =‘1’时,SHOW_NEW_TIME信号的赋值为‘1’,而其他信号LOAD_NEW_A、LOAD_NEW_C和SHOW_A的值此时都赋为‘0’。另外,表中关于“超时”判断处理的处理细节见VHDL源程序中的有关部分。
52
2.VHDL源程序 --整个设计中将要用到的程序包定义程序P_ALARM.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; PACKAGE P_ALARM IS SUBTYPE T_DIGITAL IS INTEGER RANGE 0 TO 9; SUBTYPE T_SHORT IS INTEGER RANGE 0 TO 65535; TYPE T_CLOCK_TIME IS ARRAY (3 DOWNTO 0) OF T_DIGITAL; TYPE T_DISPLAY IS ARRAY (3 DOWNTO 0) OF
53
STD_LOGIC_VECTOR(6 DOWNTO 0);
TYPE SEG7 IS ARRAY (0 TO 9) OF STD_LOGIC_VECTOR(6 DOWNTO 0); CONSTANT SEVEN_SEG: SEG7 := (
54
“ ”, “ ”, “ ”, " ", " ", " ", " ", " ", " ', " " );
55
TYPE KEYPAD9 IS ARRAY (0 TO 9) OF STD_LOGIC_VECTOR(9 DOWNTO 0);
CONSTANT KEYNUMBER: KEYPAD9 := (
56
" ", -- 0 " ", -- 1 " ", -- 2 " ", -- 3 " ", -- 4 " ", -- 5 " ", -- 6 " ", -- 7 " ", -- 8 " " ); END PACKAGE P_ALARM;
57
-- 控制器源程序ALARM_CONTROLLER.VHD
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_CONTROLLER IS PORT( KEY :IN STD_LOGIC; ALARM_BUTTON :IN STD_LOGIC; TIME_BUTTON :IN STD_LOGIC; CLK :IN STD_LOGIC;
58
RESET :IN STD_LOGIC; LOAD_NEW_A :OUT STD_LOGIC; LOAD_NEW_C :OUT STD_LOGIC; SHOW_NEW_TIME :OUT STD_LOGIC; SHOW_A :OUT STD_LOGIC); END ENTITY ALARM_CONTROLLER; ARCHITECTURE ART OF ALARM_CONTROLLER IS TYPE T_STATE IS (S0, S1, S2, S3,S4); CONSTANT KEY_TIMEOUT :T_SHORT := 500;
59
CONSTANT SHOW_ALARM_TIMEOUT : T_SHORT := 500;
SIGNAL CURR_STATE : T_STATE; SIGNAL NEXT_STATE : T_STATE; SIGNAL COUNTER_K : T_SHORT; SIGNAL ENABLE_COUNT_K : STD_LOGIC; SIGNAL COUNT_K_END : STD_LOGIC; SIGNAL COUNTER_A : T_SHORT; SIGNAL ENABLE_COUNT_A : STD_LOGIC; SIGNAL COUNT_A_END : STD_LOGIC; BEGIN
60
PROCESS(CLK,RESET) IS
BEGIN IF RESET ='1' THEN CURR_STATE <= S0; ELSIF RISING_EDGE(CLK) THEN CURR_STATE <= NEXT_STATE; END IF; END PROCESS;
61
PROCESS(KEY, ALARM_BUTTON, TIME_BUTTON, CURR_STATE,
COUNT_A_END,COUNT_K_END) IS BEGIN NEXT_STATE <= CURR_STATE; LOAD_NEW_A <= '0'; LOAD_NEW_C <= '0'; SHOW_A <= '0'; SHOW_NEW_TIME <= '0'; ENABLE_COUNT_K <= '0'; ENABLE_COUNT_A <= '0';
62
CASE CURR_STATE IS WHEN S0 => IF (KEY = '1') THEN NEXT_STATE <= S1; SHOW_NEW_TIME <= '1'; ELSIF (ALARM_BUTTON = '1') THEN NEXT_STATE <= S4; SHOW_A <= '1'; ELSE NEXT_STATE <= S0; END IF;
63
WHEN S1 => IF (KEY = '1') THEN NEXT_STATE <= S1; ELSIF (ALARM_BUTTON = '1') THEN NEXT_STATE <= S2; LOAD_NEW_A <= '1'; ELSIF (TIME_BUTTON = '1') THEN NEXT_STATE <= S3; LOAD_NEW_C <= '1'; ELSE IF (COUNT_K_END = '1') THEN NEXT_STATE <= S0;
64
ELSE NEXT_STATE <= S1; END IF; ENABLE_COUNT_K <= '1'; SHOW_NEW_TIME <= '1'; WHEN S2 => IF (ALARM_BUTTON = '1') THEN NEXT_STATE <= S2; LOAD_NEW_A <= '1'; NEXT_STATE <= S0;
65
WHEN S3 => IF (TIME_BUTTON = '1') THEN NEXT_STATE <= S3; LOAD_NEW_C <= '1'; ELSE NEXT_STATE <= S0; END IF; WHEN S4 => IF (KEY = '1') THEN NEXT_STATE <= S1;
66
ELSE NEXT_STATE <= S4; IF (COUNT_A_END = '1') THEN NEXT_STATE <= S0; SHOW_A <= '1';
67
END IF; ENABLE_COUNT_A <= '1'; WHEN OTHERS => NULL; END CASE; END PROCESS;
68
COUNT_KEY : PROCESS(ENABLE_COUNT_K, CLK) IS
BEGIN IF (ENABLE_COUNT_K = '0') THEN COUNTER_K <= 0; COUNT_K_END <= '0'; ELSIF (RISING_EDGE(CLK)) THEN IF (COUNTER_K >= KEY_TIMEOUT) THEN COUNT_K_END <= '1'; ELSE
69
COUNTER_K <= COUNTER_K + 1;
END IF; END PROCESS COUNT_KEY; COUNT_ALARM : PROCESS(ENABLE_COUNT_A, CLK) IS BEGIN IF (ENABLE_COUNT_A = '0') THEN COUNTER_A <= 0;
70
COUNT_A_END <= '0'; ELSIF RISING_EDGE(CLK) THEN IF (COUNTER_A >= SHOW_ALARM_TIMEOUT) THEN COUNT_A_END <= '1'; ELSE COUNTER_A <= COUNTER_A + 1; END IF; END PROCESS COUNT_ALARM; END ARCHITECTURE ART;
71
闹钟系统的译码器的设计 1.设计思路 本模块的功能是将每次按下闹钟系统的数字键盘后产生的一个数字所对应的10位二进制数据信号转换为1位十进制整数信号,以作为小时、分钟计数的四个数字之一,如图6.16所示。其中,KEYPAD为输入端口,接收10位二进制数据信号;VALUE为输出端口,输出相应的1位十进制整数信号。输入数据与输出数据的译码关系见表6.2。
72
图6.16 电路系统示意图
73
表6.2 输入、输出数据的译码关系
74
2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY DECODER IS PORT(KEYPAD :IN STD_LOGIC_VECTOR(9 DOWNTO 0); VALUE :OUT T_DIGITAL); END ENTITY DECODER; ARCHITECTURE ART OF DECODER IS
75
BEGIN WITH KEYPAD SELECT VALUE <= 0 WHEN “ ”, 1 WHEN “ ”, 2 WHEN “ ”, 3 WHEN “ ”, 4 WHEN “ ”, 5 WHEN “ ”, 6 WHEN “ ”, 7 WHEN “ ”,
76
8 WHEN “ ”, 9 WHEN “ ”, 0 WHEN OTHERS; END ARCHITECTURE ART;
77
闹钟系统的移位寄存器的设计 1.设计思路 本模块的功能是在CLK端口输入信号的上升沿同步下,将KEY端口的输入信号移入NEW_TIME 端口的输出信号最低位,原有信息依次向左移,最高位信息丢失;RESET端口的输入信号对NEW_TIME端口输出信号进行异步清零复位。电路系统示意图如图6.17所示。
78
图6.17 移位寄存器电路示意图
79
2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY KEY_BUFFER IS PORT(KEY :IN T_DIGITAL; CLK :IN STD_LOGIC; RESET :IN STD_LOGIC; NEW_TIME:OUT T_CLOCK_TIME); END ENTITY KEY_BUFFER;
80
ARCHITECTURE ART OF KEY_BUFFER IS
SIGNAL N_T:T_CLOCK_TIME; BEGIN SHIFT:PROCESS(RESET,CLK) IS IF (RESET = '1') THEN N_T <= (0,0,0,0); ELSIF (CLK'EVENT AND CLK = '1' )THEN FOR I IN 3 DOWNTO 1 LOOP N_T(I) <= N_T(I-1);
81
END LOOP; N_T(0) <= KEY; END IF; END PROCESS SHIFT; NEW_TIME <= N_T; END ARCHITECTURE ART;
82
闹钟系统的闹钟寄存器和时间计数器的设计 1.电路系统工作原理 闹钟寄存器模块的功能是在时钟上升沿同步下,根据LOAD_NEW_A端口的输入信号控制ALARM_TIME端口的输出;当控制信号有效(高电平)时,把NEW_ALARM_TIME端口的输入信号值输出;RESET端口输入信号对ALARM_TIME端口的输出进行异步的清零复位。图6.18是闹钟寄存器模块的示意图。
83
图6.18 闹钟寄存器示意图
84
闹钟系统的闹钟时间由闹钟寄存器保存和传递,而当前时间由时间计数器保存、传递并按分钟累加推进。这两个组件的功能和设计描述比较相似,它们之间的区别主要在于自动累加功能的有无和控制信号的优先作用次序。
85
图6.19 时间计数器示意图
86
时间计数器模块的功能是当RESET端口输入信号为高电平时,对CURRENT_TIME端口输出信号清零复位;当LOAD_NEW_C端口输入信号为高电平时,将NEW_CURRENT_TIME端口的输入信号输出给CURRENT_TIME端口。RESET端口的控制优先于LOAD_NEW_C端口。当这两个控制信号都无效时,在时钟上升沿同步下,对CURRENT_TIME端口输出信号累加1,并根据小时、分钟的规律处理进位。图6.19是时间计数器模块的示意图。
87
2.VHDL源程序 --时间计数器的源程序ALARM_COUNTER.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_COUNTER IS PORT(NEW_CURRENT_TIME:IN T_CLOCK_TIME; LOAD_NEW_C:IN STD_LOGIC; CLK:IN STD_LOGIC;
88
RESET:IN STD_LOGIC; CURRENT_TIME:OUT T_CLOCK_TIME); END ENTITY ALARM_COUNTER; ARCHITECTURE ART OF ALARM_COUNTER IS SIGNAL I_CURRENT_TIME : T_CLOCK_TIME; BEGIN PROCESS(CLK,RESET,LOAD_NEW_C) IS VARIABLE C_T:T_CLOCK_TIME; IF RESET = '1' THEN
89
I_CURRENT_TIME <= (0,0,0,0);
ELSIF LOAD_NEW_C ='1' THEN I_CURRENT_TIME <= NEW_CURRENT_TIME; ELSIF RISING_EDGE(CLK) THEN C_T := I_CURRENT_TIME; IF C_T(0) < 9 THEN C_T(0) := C_T(0) + 1;
90
ELSE C_T(0) := 0; IF C_T(1) < 5 THEN C_T(1) := C_T(1) + 1; C_T(1) := 0; IF C_T(3) < 2 THEN IF C_T(2) < 9 THEN C_T(2) := C_T(2) + 1; C_T(2) := 0; C_T(3) := C_T(3) + 1; END IF;
91
ELSE IF C_T(2) < 3 THEN C_T(2) := C_T(2) + 1; C_T(2) := 0; C_T(3) := 0; END IF; I_CURRENT_TIME <= C_T;
92
END PROCESS; CURRENT_TIME <= I_CURRENT_TIME; END ARCHITECTURE ART; --闹钟寄存器的源程序ALARM_REG.VHD LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_REG IS
93
PORT(NEW_ALARM_TIME:IN T_CLOCK_TIME;
LOAD_NEW_A :IN STD_LOGIC; CLK :IN STD_LOGIC; RESET :IN STD_LOGIC; ALARM_TIME:OUT T_CLOCK_TIME); END ENTITY ALARM_REG; ARCHITECTURE ART OF ALARM_REG IS BEGIN PROCESS(CLK,RESET) IS
94
IF RESET = '1' THEN ALARM_TIME <= (0,0,0,0); ELSE IF RISING_EDGE(CLK) THEN IF LOAD_NEW_A = '1' THEN ALARM_TIME <= NEW_ALARM_TIME; ELSIF LOAD_NEW_A /= '0' THEN ASSERT FALSE REPORT“UNCERTAIN LOAD_NEW_ALARM CONTROL!” SEVERITY WARNING;
95
END IF; END PROCESS; END ARCHITECTURE ART;
96
闹钟系统的显示驱动器的设计 1.设计思路 本模块的功能是:当SHOW_NEW_TIME端口输入信号有效(高电平)时,根据NEW_TIME端口输入信号(时间数据),产生相应的四个七段数码显示器的驱动数据,并在DISPLAY端口输出该信号。
97
当SHOW_NEW_TIME端口输入信号无效(低电平)时,判断SHOW_A端口的输入信号,为高电平时,根据ALARM_TIME端口的输入信号(时间数据)产生相应的四个七段数码显示器的驱动数据,并在DISPLAY端口输出该信号;为低电平时,根据CURRENT_TIME端口的输入信号,对DISPLAY端口进行驱动。当ALARM_TIME 端口的输入信号值与CURRENT_TIME端口的输入信号值相同时,SOUND_ALARM端口的输出信号有效(高电平),反之无效。图6.20为显示驱动器示意图。
98
图6.20 显示驱动器示意图
99
2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY DISPLAY_DRIVER IS PORT(ALARM_TIME :IN T_CLOCK_TIME; CURRENT_TIME :IN T_CLOCK_TIME; NEW_TIME :IN T_CLOCK_TIME; SHOW_NEW_TIME:IN STD_LOGIC; SHOW_A :IN STD_LOGIC; SOUND_ALARM :OUT STD_LOGIC; DISPLAY:OUT T_DISPLAY);
100
END ENTITY DISPLAY_DRIVER;
ARCHITECTURE ART OF DISPLAY_DRIVER IS SIGNAL DISPLAY_TIME:T_CLOCK_TIME; BEGIN CTRL:PROCESS(ALARM_TIME,CURRENT_TIME,NEW_TIME,SHOW_A,SHOW_NEW_TIME) IS
101
SOUND_LP: FOR I IN ALARM_TIME'RANGE LOOP
IF NOT(ALARM_TIME(I) = CURRENT_TIME(I)) THEN SOUND_ALARM <= '0'; EXIT SOUND_LP; ELSE SOUND_ALARM <= '1'; END IF;
102
END LOOP SOUND_LP; IF SHOW_NEW_TIME = '1' THEN DISPLAY_TIME <= NEW_TIME; ELSIF SHOW_A = '1' THEN DISPLAY_TIME <= ALARM_TIME; ELSIF SHOW_A = '0' THEN DISPLAY_TIME <= CURRENT_TIME; ELSE
103
ASSERT FALSE REPORT “UNCERTAIN DISPLAY_DRIVER CONTROL!”
SEVERITY WARNING; END IF; END PROCESS CTRL; DISP:PROCESS(DISPLAY_TIME) IS BEGIN
104
FOR I IN DISPLAY_TIME'RANGE LOOP
DISPLAY(I) <= SEVEN_SEG(DISPLAY_TIME(I)); END LOOP; END PROCESS DISP; END ARCHITECTURE ART;
105
闹钟系统的分频器的设计 1.设计思路 本模块的功能是将CLK_IN端口输入的时钟信号分频后送给CLK_OUT端口;当RESET端口输入信号有效(高电平)时,CLK_OUT端口输出信号清零。图6.21为分频器示意图。
106
图6.21 分频器示意图
107
2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE WORK.P_ALARM.ALL; ENTITY FQ_DIVIDER IS PORT( CLK_IN:IN STD_LOGIC; RESET:IN STD_LOGIC; CLK_OUT:OUT STD_LOGIC );
108
END ENTITY FQ_DIVIDER;
ARCHITECTURE ART OF FQ_DIVIDER IS CONSTANT DIVIDE_PERIOD : T_SHORT := 6000; BEGIN DIVIDE_CLK: PROCESS(CLK_IN,RESET) IS VARIABLE CNT : T_SHORT; IF (RESET = '1') THEN CNT := 0; CLK_OUT <= '0';
109
ELSIF RISING_EDGE(CLK_IN) THEN
IF (CNT < (DIVIDE_PERIOD/2)) THEN CLK_OUT <= '1'; CNT := CNT + 1; ELSIF (CNT < (DIVIDE_PERIOD-1)) THEN CLK_OUT <= '0';
110
ELSE CNT := 0; END IF; END PROCESS DIVIDE_CLK; END ARCHITECTURE ART;
111
闹钟系统的整体组装 1.整体组装说明 前边已经完成了计时器各个组成部分的设计,下面把这些组成部分组装起来,形成完整的总体设计。该计时器命名为ALARM_CLOCK,其外部端口如图6.22所示。
112
图6.22 计时器的外部端口
113
各个输入/输出端口的作用如下: (1) CLK为外部时钟信号,RESET为复位信号。 (2) KEYPAD是一个10位信号,若其中某一位为高电平,则表示用户按下了相应下标的数字键。 (3) 当KEYDOWN为高电平时(KEYDOWN= '1'),表示用户按下某一数字键。 (4) 当ALARM_BUTTON为高电平时,表示用户按下ALARM键。 (5) 当TIME_BUTTON为高电平时,表示用户按下TIME键。
114
(6) DISPLAY实际上表示了四个七段数码显示管,用于显示时间,如12∶20。
(7) SOUND_ALARM用于控制扬声器发声,当SOUND_ALARM = '1'时,扬声器发出蜂鸣,表示到了设定的闹钟时间。 设计的总体结构图如图6.23所示。
115
图6.23 总体结构
116
下面再简要说明各组成部分的功能: (1) 译码器(DECODER) 可将KEYPAD信号转换为0~9的整型数,以直观地表示和处理用户输入的数字。 (2) 键盘缓冲器(KEY_BUFFER)是一个移位寄存器,暂存用户键入的数字,并且实现用户键入数字在显示器上从右到左的依次显示。这里需要注意的是,由图6.23可以看出,KEY_BUFFER的时钟端连接的是外部KEY_DOWN 信号。这表示用户每输入一个数字,KEY_BUFFER移位一次。
117
(3) 分频器(FQ_DIVIDER)将较高速的外部时钟频率分频成每分钟一次的时钟频率,以便进行时钟计数。
(4) 计数器(ALARM_COUNTER)实际上是一个异步复位、异步置数的累加器,通常情况下进行时钟累加计数,必要时可置入新的时钟值,然后从该值开始新的计数。 (5) 寄存器(ALARM_REG)用于保存用户设置的闹钟时间,是一个异步复位寄存器。
118
(6) 显示器(DISPLAY_DRIVER)根据需要显示当前时间、用户设置的闹钟时间或用户通过键盘输入的新的时间,同时判断当前时间是否已到了闹钟时间,实际上是一个多路选择器加比较器。
(7) 控制器(ALARM_CONTROLLER)是设计的核心部分,按设计要求产生相应的控制逻辑,以控制其他各部分的工作。
119
2.VHDL源程序 LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; USE WORK.P_ALARM.ALL; ENTITY ALARM_CLOCK IS PORT(KEYPAD : IN STD_LOGIC_VECTOR(9 DOWNTO 0); KEY_DOWN : IN STD_LOGIC; ALARM_BUTTON: IN STD_LOGIC; TIME_BUTTON : IN STD_LOGIC;
120
CLK : IN STD_LOGIC; RESET : IN STD_LOGIC; DISPLAY : OUT T_DISPLAY; SOUND_ALARM : OUT STD_LOGIC); END ENTITY ALARM_CLOCK; ARCHITECTURE ART OF ALARM_CLOCK IS COMPONENT DECODER IS PORT( KEYPAD :IN STD_LOGIC_VECTOR(9 DOWNTO 0); VALUE :OUT T_DIGITAL); END COMPONENT DECODER;
121
... SIGNAL S0 : T_DIGITAL; SIGNAL S1,S2,S3,S4,S5 : STD_LOGIC; SIGNAL S6,S7,S8 : T_CLOCK_TIME; BEGIN U1: DECODER PORT MAP(KEYPAD, S0); U2: KEY_BUFFER PORT MAP(S0, KEY_DOWN,RESET, S6); U3: ALARM_CONTROLLER PORT MAP(KEY_DOWN,ALARM_BUTTON,TIME_BUTTON,
122
CLK,RESET,S1,S2,S3,S4); U4: ALARM_COUNTER PORT MAP(S6,S2,S5,RESET,S8); U5: ALARM_REG PORT MAP(S6,S1,CLK,RESET,S7); U6: DISPLAY_DRIVER PORT MAP(S7,S6,S8,S3,S4,SOUND_ALARM,DISPLAY); U7: FQ_DIVIDER PORT MAP(CLK,RESET,S5); END ARCHIITECTURE ART;
123
闹钟系统的硬件验证 若用GW48型EDA实验开发系统进行硬件验证,考虑到实验开发系统提供的输入信号按键的有限,可将输入数字按键0~9改为一个按键,该按键的信号作为一个8421码信号发生器的输入,由8421码信号发生器输出数字0~9。同时,每输入完一个数字后应增加一个输入确认键。具体验证方案由读者自行完成。
Similar presentations