定时器VHDL设计(特制材料)
![定时器VHDL设计(特制材料)](https://img.360docs.net/imgd3/1oreu483g2aywj75lnl0xy2c7ononxqe-31.webp)
![定时器VHDL设计(特制材料)](https://img.360docs.net/imgd3/1oreu483g2aywj75lnl0xy2c7ononxqe-f2.webp)
定时器
1.实验任务
设计要求:整体清零;可以定时最高到99min;以秒速度递增至预定时间,以分速度递减至零。
总体框图如下图所示:
clr 用来整体复位清零;clk 提供了秒信号,频率为1HZ(在仿真中取10MHZ);clky 是用来扫描输出的,选用频率大于50HZ的方波(为便于观察结果,在仿真中取10MHZ);set 是用来置位的,低电平时有效,将以秒的速度,从零递增到所需定时的时间,为高电平时以分的速度递减,实现定时,直到零,定时结束;alm 输出高电平,可启动各种电路或发出警报。时间的变化都将在数码管上显示出来。
2.模块及模块功能
模块AAA见下图示。它是核心模块,用来实现定时器的逻辑功能,计数结果用十进制数输出。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY aaa IS
PORT(clk, clr, set: in std_logic;
alm: out std_logic;
q1,q0: out std_logic_vector(3 downto 0));
END aaa;
ARCHITECTURE aaa_arc OF aaa IS
BEGIN
PROCESS (clk,clr)
variable cnt1,cnt0:std_logic_vector(3 downto 0);
variable cnt: integer range 0 to 59;
BEGIN
IF clr='0' THEN --整体复位
alm<='0';
cnt:=0;
cnt1:="0000";
cnt0:="0000";
ELSIF clk'EVENT AND clk='1' THEN --设计数初值
IF set='0' THEN
cnt:=0;
IF cnt0<"1001" THEN
cnt0:=cnt0+1;
ELSE
cnt0:="0000";
IF cnt1<"1001" THEN
cnt1:=cnt1+1;
ELSE
cnt1:="0000";
END IF;
END IF;
ELSE
IF cnt<59 THEN --60分频
cnt:=cnt+1;
ELSE
cnt:=0;
IF cnt0>"0000" THEN
cnt0:=cnt0-1;
IF cnt1="0000" AND cnt0="0000" THEN --判断计时是否结束
alm<='1';
END IF;
ELSE
cnt0:="1001";
IF cnt1>"0000" THEN
cnt1:=cnt1-1;
ELSE
cnt1:="1001";
END IF;
END IF;
END IF;
END IF;
END IF;
q0<=cnt0;
q1<=cnt1;
END PROCESS;
END aaa_arc;
模块CH如下图示。由于只用了两个数码管,所以片选信号直接接一个较快的时钟。此模块的功能是对应片选信号,送出要显示的数据。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY ch IS
PORT(sel:in std_logic;
a1,a0:in std_logic_vector(3 downto 0);
q:out std_logic_vector(3 downto 0));
END ch;
ARCHITECTURE ch_arc OF ch IS
BEGIN
PROCESS(sel,a0,a1)
BEGIN
IF sel='0' THEN
q<=a0;
ELSE
q<=a1;
END IF;
END PROCESS;
END ch_arc;
模块DISP如下图示。该模块为七段译码器。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY disp IS
PORT(a:in std_logic_vector(3 downto 0);
q:out std_logic_vector(6 downto 0)); END disp;
ARCHITECTURE disp_arc OF disp IS BEGIN
PROCESS(a)
BEGIN
CASE a IS
WHEN "0000"=>q<="0111111";
WHEN "0001"=>q<="0000110";
WHEN "0010"=>q<="1011011";
WHEN "0011"=>q<="1001111";
WHEN "0100"=>q<="1100110";
WHEN "0101"=>q<="1101101";
WHEN "0110"=>q<="1111101";
WHEN "0111"=>q<="0000111";
WHEN "1000"=>q<="1111111";
WHEN "1001"=>q<="1101111";
WHEN others=>q<="0000000";
END CASE;
END PROCESS;
END disp_arc;
3.仿真结果分析
总体仿真结果如下:
由图可见,clr =’0’可实现整体复位功能。set =’0’,输出以秒的速度从零递增。
本图中当递增到26后,set =’1’,输出经60分频后以分的速度递减,实现定时,直到零,定时结束。
定时结束后,clm =’1’,此时可启动各种电路或发出报警,定时结束。
clr =’0’,整体复位,clm =’0’。
该设计采用动态扫描电路,经过二选一模块将结果显示出来。从上图可见,q交替输出两位结果。sel=’1’时输出高位,sel=’0’时输出低位。
自动售货机控制器
一、设计一个自动售货机的控制电路。该自动售货机销售价格为25美分的糖果,利用有限状态机进行电路设计。
控制器的输入输出如图所示:
输入信号是nickel_in(投入5美分),dime_in(投入10美分),quarter_in(投入25美分)。另外两个必要的输入是clk(时钟)和rst(复位)。控制器相应的有3个输出:candy_out用于控制发放糖果, nickel_out用于控制找回5美分的零钱, dime_out用于控制找回10美分的零钱。
上图给出了有限状态机的状态转移图。圆圈里的数代表顾客投进来的总钱数(接受5美分、10美分或25美分的硬币)。状态0是空闲状态。从它开始,如果投入5美分硬币,将跳转到状态5;如果投入10美分硬币,将跳转到状态10;如果投入25美分硬币,将跳转到状态25。随着投币数量的增加,状态不断跳转,如果投入的币值达到25美分,就可以进入状态25,然后售货机会发放糖果,并跳转回状态0。如果投入的币值超过了25美分,那么售货机要进入与找零钱相关的状态。例如,当投入的币值达到40美分时,需要先退出5美分硬币(进入状态35),然后再退出10美分,发放糖果并进入状态0。
二、该设计的VHDL 源码如下:
在代码中定义了枚举类型state ,它包含10个状态,所以至少需要用4位对其进行编码(将产生4个寄存器)。在默认状态下,编译器将按照它们的排列顺序对其进行编码,所以有st0=”0000”(十进制的0),st5=”0001”(十进制的1),…和st45=”1001”(十进制的9)。在仿真中,这些数字将替代状态的名称出现在仿真波形中。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY vending_machine IS
PORT (clk, rst:IN STD_LOGIC;
nickel_in, dime_in, quarter_in: IN BOOLEAN;
candy_out, nickel_out, dime_out: OUT STD_LOGIC);
25
5
10 15 20 40
45
30
35
ni
ni
ni
ni qi qi
qi
qi
qi
no
do
di no+co
do+co
co
di
di
di
di ni
自动售货机控制器的顶层电路图和状态转移图
信号说明:ni=nickel_in, di=dime_in, qi=quarter_in, no=nickel_out, do=dime_out,
co=candy_out
END vending_machine;
ARCHITECTURE fsm OF vending_machine IS
TYPE state IS(st0,st5,st10,st15,st20,st25,st30,st35,st40,st45);
SIGNAL present_state,next_state: STA TE;
BEGIN
PROCESS(rst,clk)
BEGIN
IF(rst='1') THEN
present_state<=st0;
ELSIF (clk'EVENT AND clk='1') THEN
present_state<=next_state;
END IF;
END PROCESS;
PROCESS(present_state, nickel_in, dime_in, quarter_in)
BEGIN
CASE present_state IS
WHEN st0=>
candy_out<='0';
nickel_out<='0';
dime_out<='0';
IF(nickel_in) THEN next_state<=st5;
ELSIF(dime_in) THEN next_state<=st10;
ELSIF(quarter_in) THEN next_state<=st25;
ELSE next_state<=st0;
END IF;
WHEN st5=>
candy_out<='0';
nickel_out<='0';
dime_out<='0';
IF(nickel_in) THEN next_state<=st10;
ELSIF(dime_in) THEN next_state<=st15;
ELSIF(quarter_in) THEN next_state<= st30;
ELSE next_state<=st5;
END IF;
WHEN st10=>
candy_out<='0';
nickel_out<='0';
dime_out<='0';
IF(nickel_in) THEN next_state<=st15;
ELSIF(dime_in) THEN next_state<=st20;
ELSIF(quarter_in) THEN next_state<=st35;
ELSE next_state<=st10;
END IF;
WHEN st15=>
candy_out<='0';
nickel_out<='0';
dime_out<='0';
IF(nickel_in) THEN next_state<=st20;
ELSIF(dime_in) THEN next_state<=st25;
ELSIF(quarter_in) THEN next_state<=st40;
ELSE next_state<=st15;
END IF;
WHEN st20=>
candy_out<='0';
nickel_out<='0';
dime_out<='0';
IF(nickel_in) THEN next_state<=st25;
ELSIF(dime_in) THEN next_state<=st30;
ELSIF(quarter_in) THEN next_state<=st45;
ELSE next_state<=st20;
END IF;
WHEN st25=>
candy_out<='1';
nickel_out<='0';
dime_out<='0';
next_state<=st0;
WHEN st30=>
candy_out<='1';
nickel_out<='1';
dime_out<='0';
next_state<=st0;
WHEN st35=>
candy_out<='1';
nickel_out<='0';
dime_out<='1';
next_state<=st0;
WHEN st40=>
candy_out<='0';
nickel_out<='1';
dime_out<='0';
next_state<=st35;
WHEN st45=>
candy_out<='0';