一 设计任务及要求
设计一个可容纳四组参赛者同时抢答的数字抢答器。
(1)能判断第一抢答者并报警指示抢答成功,其他组抢答均无效;
(2)设计倒计时时钟,若提前抢答则对相应的抢答组发出警报。
二、设计原理简介
2.1 数字式竞赛抢答器工作流程:
图1.1 数字式竞赛抢答器工作流程
2.2 状态控制模块原理
状态控制模块的目标是区分提前抢答和正常抢答两个不同状态,并且确保第一抢答者并报警指示抢答成功,其他组抢答均无效。基于此目标,状态控制控制模块的设计原则便是,依据数字抢答器的工作原理逻辑,定义不同的状态,以及确定不同状态之间进行切换的控制条件。
数字抢答器应当包括两层状态,更加基本的三个状分别是闲置状态、倒计时状态以及正常抢答状态。其中,倒计时状态又引申出各组参赛者提前抢答状态,而正常抢答状态引申出各组参赛者首先抢答状态。
考虑基本的三个状态之间切换的限制条件,引入一个开始信号,将闲置状态改变为倒计时状态;倒计时自然结束后,状态改变为正常抢答状态;此外,引入一个复位信号,不论当时处于什么状态,接收到复位信号后,均恢复为闲置状态。
考虑倒计时引申出的状态,在倒计时还未归零前,4个参赛组分别对应的key1到key4信号任意有一个被接收时,即进入对应组别的提前抢答状态,除复位信号可以使得这四个状态回到闲置状态以外,不再设置其它可以改变状态的信号,这样就可以确保判断第一抢答组的组别。
考虑正常抢答状态引申出的状态,分别对应4个组别的抢答成功状态,同样,不设置复位按键以外可以切换这四个状态的信号,以确保可以判断第一抢答组的组别。
综上所述,一共有11个状态,包括三个基本状态:闲置、倒计时以及正常抢答;八个引申状态,1-4号提前抢答状态以及1-4号正常抢答状态。逻辑如下图:
图1.2 状态切换流程图
2.3 倒计时显示模块原理
倒计时功能是配合倒计时状态的功能,基本而言,倒计时时间没有归0时,处于倒计时状态,归0后处于正常抢答状态。为实现其对状态切换的控制功能,需要一个信号倒计时来赋值处理,引入一个downtime信号,使用10秒倒计时,为方便后续使用经典的七段数码管驱动电路来实现显示,采用四位二进制存储,最后效果要求从10秒倒计时到0.我们已经知道,系统提供的时钟信号是50MHz,引入一个clk_1Hz,对clk信号的高低电平切换进行计数,每有一次,i加一,当i记录到50M时,将clk计数清0,同时clk_1Hz赋值为高电平,i不等于50M时令clk_1Hz等于0.每当clk_1Hz等于1时,令倒计时信号减一。当然,倒计时在接收到开始信号时从9开始减少。逻辑如下图。
图1.3 倒计时秒钟信号发生器
对于数码管显示,将对应4位二进制码转换为8位数码管对应码(如下表)即可完成数码管显示。
表1 七位数码管对应图
2.4 抢答对应提示与报警功能模块原理
这一模块分为正常抢答的提示部分和提前抢答的警告部分,可以利用对应的8个引申状态为前提,来控制对应的提示和警报功能。该代码以led灯长亮与蜂鸣器长鸣作为提示信号,以led灯闪烁和蜂鸣器间断发出鸣叫来作为警报信号。对于长亮和长鸣,只要分别赋予led灯和蜂鸣器以低电平,令其在对应正常抢答状态正常工作即可,对于闪烁和间断,受1Hz时钟信号的启发,采用同样的方法,使得1秒50M分为4个12.5M令clk_2Hz信号反转4次,利用非1=0,非0=1,即可实现2Hz的时钟信号。
然后在1组正常抢答状态下,令1号led灯常亮,蜂鸣器长鸣;2组正常抢答状态下,令2号led灯常亮,蜂鸣器长鸣;3组正常抢答状态下,令3号led灯常亮,蜂鸣器长鸣;4组正常抢答状态下,令4号led灯常亮,蜂鸣器长鸣;
在1组提前抢答状态下,令1号led灯闪烁,蜂鸣器间断发出声响;在2组提前抢答状态下,令2号led灯闪烁,蜂鸣器间断发出声响;在3组提前抢答状态下,令3号led灯闪烁,蜂鸣器间断发出声响;在4组提前抢答状态下,令4号led灯闪烁,蜂鸣器间断发出声响;
图1.4 2Hz时钟信号发生器
三、设计方案与实现
3.1 设计软件环境搭建
本设计使用软件QUARTUS II 13.0开发,使用VHDL语言编写,采用ModelSi Altera进行仿真。新建工程文件命名为qiangdaqi,并新建control.vhd、div.vhd、LED7S.vhd等文件。
之后按照Processing--Start--Start Test Bench Template Writer运行,编写好.tbh仿真模板的文件,进入Assignments--setting导入仿真模板。
注:设置仿真工具路径:Tools--options--EDA Tool Options
3.2 仿真效果
图2.3 key1组提前抢答
分析:可以看到,可以看到7位数码管输出(10011001)对应的倒计时为4,不为0,key1按下,导致led1闪烁,beep间断性鸣叫
图2.4 key3组正常抢答
分析:可以看到7位数码管输出(11000000)对应的倒计时为0,即在正常抢答状态下,第三组先抢答成功,led3亮起(低电平)且beep正常鸣叫(低电平),且随后第四组抢答已经无效。
3.3管脚
图2.5 管脚图
四、仿真结果分析
4.1 调试流程
调试流程:我们使用的芯片是EDA MAXII EPM 240T100C5,通过下载相关芯片库并存放于quartus的bin文件夹中,选择正确的芯片进行编程,代码编译成功后。将开发板的电源线与JIAG接口与电脑相连,之后首先在设备管理器-通用串行总线控制器中将usb-blaster的数字驱动进行更新,随后在programmer中检测到usb0接口,加入编译生成的.pof文件后,勾选program/configure,点击开始,加载到100%后烧录成功。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--控制模块
ENTITY control IS
PORT (
clk : IN STD_LOGIC;--时钟
rst_n : IN STD_LOGIC;--复位
start_n : IN STD_LOGIC;--开始
key_1 : IN STD_LOGIC;--按键1
key_2 : IN STD_LOGIC;--按键2
key_3 : IN STD_LOGIC;--按键3
key_4 : IN STD_LOGIC;--按键4
clk_1Hz : IN STD_LOGIC;---1Hz信号
clk_2Hz : IN STD_LOGIC;--2Hz信号
LED1 : OUT STD_LOGIC;--LED1
LED2 : OUT STD_LOGIC;--LED2
LED3 : OUT STD_LOGIC;--LED3
LED4 : OUT STD_LOGIC;--LED4
beep : OUT STD_LOGIC;--蜂鸣器
down_time : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)--倒计时
);
END control;
ARCHITECTURE behave OF control IS
type state_type is(s_idle,s_downcnt,s_start,s_qiangda_1,s_qiangda_2,s_qiangda_3,s_qiangda_4,s_early_1,s_early_2,s_early_3,s_early_4);
SIGNAL state : state_type;
SIGNAL time_cnt : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
BEGIN
--状态机
PROCESS (clk, rst_n)
BEGIN
IF (rst_n = '0') THEN
state <= s_idle;--复位
ELSIF (clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN s_idle =>--空闲状态
IF (start_n = '0') THEN
state <= s_downcnt;
ELSE
state <= s_idle;
END IF;
WHEN s_downcnt =>--倒计时状态
IF (key_1 = '0') THEN
state <= s_early_1;--提前抢答1
ELSIF (key_2 = '0') THEN
state <= s_early_2;--提前抢答2
ELSIF (key_3 = '0') THEN
state <= s_early_3;--提前抢答3
ELSIF (key_4 = '0') THEN
state <= s_early_4;--提前抢答4
ELSIF (time_cnt = "0000") THEN
state <= s_start;
ELSE
state <= s_downcnt;
END IF;
WHEN s_start =>--开始抢答
IF (key_1 = '0') THEN
state <= s_qiangda_1;--正常抢答1
ELSIF (key_2 = '0') THEN
state <= s_qiangda_2;--正常抢答2
ELSIF (key_3 = '0') THEN
state <= s_qiangda_3;--正常抢答3
ELSIF (key_4 = '0') THEN
state <= s_qiangda_4;--正常抢答4
ELSE
state <= s_start;
END IF;
WHEN OTHERS =>
state <= state;
END CASE;
END IF;
END PROCESS;
--倒计时
PROCESS (clk, rst_n)
BEGIN
IF (rst_n = '0') THEN
time_cnt <= "1001";--9开始
ELSIF (clk'EVENT AND clk = '1') THEN
IF (state = s_downcnt) THEN
IF (clk_1Hz = '1') THEN--1Hz
time_cnt <= time_cnt - "0001";--倒计时
ELSE
time_cnt <= time_cnt;
END IF;
ELSE
time_cnt <= time_cnt;
END IF;
END IF;
END PROCESS;
down_time <= time_cnt;--输出倒计时
--LED1
PROCESS (clk, rst_n)
BEGIN
IF (rst_n = '0') THEN
LED1 <= '1';
ELSIF (clk'EVENT AND clk = '1') THEN
IF (state = s_qiangda_1) THEN
LED1 <= '0';--正常抢答亮
ELSIF (state = s_early_1) THEN
LED1 <= clk_2Hz;--提前抢答闪烁
ELSE
LED1 <= '1';
END IF;
END IF;
END PROCESS;
PROCESS (clk, rst_n)
BEGIN
IF (rst_n = '0') THEN
LED2 <= '1';
ELSIF (clk'EVENT AND clk = '1') THEN
IF (state = s_qiangda_2) THEN
LED2 <= '0';--正常抢答亮
ELSIF (state = s_early_2) THEN
LED2 <= clk_2Hz;--提前抢答闪烁
ELSE
LED2 <= '1';
END IF;
END IF;
END PROCESS;
PROCESS (clk, rst_n)
BEGIN
IF (rst_n = '0') THEN
LED3 <= '1';
ELSIF (clk'EVENT AND clk = '1') THEN
IF (state = s_qiangda_3) THEN
LED3 <= '0';--正常抢答亮
ELSIF (state = s_early_3) THEN
LED3 <= clk_2Hz;--提前抢答闪烁
ELSE
LED3 <= '1';
END IF;
END IF;
END PROCESS;
PROCESS (clk, rst_n)
BEGIN
IF (rst_n = '0') THEN
LED4 <= '1';
ELSIF (clk'EVENT AND clk = '1') THEN
IF (state = s_qiangda_4) THEN
LED4 <= '0';--正常抢答亮
ELSIF (state = s_early_4) THEN
LED4 <= clk_2Hz;--提前抢答闪烁
ELSE
LED4 <= '1';
END IF;
END IF;
END PROCESS;
PROCESS (clk, rst_n)
BEGIN
IF (rst_n = '0') THEN
beep <= '1';
ELSIF (clk'EVENT AND clk = '1') THEN
IF (state = s_qiangda_1 OR state = s_qiangda_2 OR state = s_qiangda_3 OR state = s_qiangda_4) THEN
beep <= '0';--正常抢答蜂鸣器提示
ELSIF (state = s_early_1 OR state = s_early_2 OR state = s_early_3 OR state = s_early_4) THEN
beep <= clk_2Hz;--提前抢答蜂鸣器间断提示
ELSE
beep <= '1';
END IF;
END IF;
END PROCESS;
END behave;
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--分频器
ENTITY div IS
PORT (
clk : IN STD_LOGIC;--50M
clk_1Hz : OUT STD_LOGIC;--1Hz
clk_2Hz : OUT STD_LOGIC--2Hz
);
END div;
ARCHITECTURE behave OF div IS
SIGNAL i : INTEGER := 0;
SIGNAL clk_2 : STD_LOGIC := '0';
SIGNAL j : INTEGER := 0;
BEGIN
PROCESS (clk)
BEGIN
IF (clk'EVENT AND clk = '1') THEN
IF (i >= 50000000) THEN--计数50000000
i <= 0;
clk_1Hz <= '1';--分频产生1Hz脉冲信号
ELSE
i <= i + 1;
clk_1Hz <= '0';
END IF;
END IF;
END PROCESS;
PROCESS (clk)
BEGIN
IF (clk'EVENT AND clk = '1') THEN
IF (j = 12500000) THEN--计数12500000
j <= 0;
clk_2 <= NOT(clk_2);--分频产生2Hz信号
ELSE
j <= j + 1;
END IF;
END IF;
END PROCESS;
clk_2Hz <= clk_2;
END behave;
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(7 downto 0));
end LED7S;
architecture one of LED7S is
begin
process(din)
begin
case din is
when "0000" => y<="11000000"; --- Display "0"
when "0001" => y<="11111001"; --- Display "1"
when "0010" => y<="10100100"; --- Display "2"
when "0011" => y<="10110000"; --- Display "3"
when "0100" => y<="10011001"; --- Display "4"
when "0101" => y<="10010010"; --- Display "5"
when "0110" => y<="10000010"; --- Display "6"
when "0111" => y<="11111000"; --- Display "7"
when "1000" => y<="10000000"; --- Display "8"
when "1001" => y<="10010000"; --- Display "9"
when "1010" => y<="10001000"; --- Display "A"
when "1011" => y<="10000011"; --- Display "B"
when "1100" => y<="11000110"; --- Display "C"
when "1101" => y<="10100001"; --- Display "D"
when "1110" => y<="10000110"; --- Display "E"
when "1111" => y<="10001110"; --- Display "F"
when others => NULL;
end case;
end process;
end one;
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY qiangdaqi_vhd_tst IS
END qiangdaqi_vhd_tst;
ARCHITECTURE qiangdaqi_arch OF qiangdaqi_vhd_tst IS
-- constants
-- signals
SIGNAL beep : STD_LOGIC;
SIGNAL clk : STD_LOGIC;
SIGNAL en : STD_LOGIC;
SIGNAL HEX : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL key_1 : STD_LOGIC;
SIGNAL key_2 : STD_LOGIC;
SIGNAL key_3 : STD_LOGIC;
SIGNAL key_4 : STD_LOGIC;
SIGNAL LED1 : STD_LOGIC;
SIGNAL LED2 : STD_LOGIC;
SIGNAL LED3 : STD_LOGIC;
SIGNAL LED4 : STD_LOGIC;
SIGNAL rst_n : STD_LOGIC;
SIGNAL start_n : STD_LOGIC;
COMPONENT qiangdaqi
PORT (
beep : OUT STD_LOGIC;
clk : IN STD_LOGIC;
en : OUT STD_LOGIC;
HEX : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
key_1 : IN STD_LOGIC;
key_2 : IN STD_LOGIC;
key_3 : IN STD_LOGIC;
key_4 : IN STD_LOGIC;
LED1 : OUT STD_LOGIC;
LED2 : OUT STD_LOGIC;
LED3 : OUT STD_LOGIC;
LED4 : OUT STD_LOGIC;
rst_n : IN STD_LOGIC;
start_n : IN STD_LOGIC
);
END COMPONENT;
BEGIN
i1 : qiangdaqi
PORT MAP (
-- list connections between master ports and signals
beep => beep,
clk => clk,
en => en,
HEX => HEX,
key_1 => key_1,
key_2 => key_2,
key_3 => key_3,
key_4 => key_4,
LED1 => LED1,
LED2 => LED2,
LED3 => LED3,
LED4 => LED4,
rst_n => rst_n,
start_n => start_n
);
init : PROCESS
BEGIN
rst_n<='0';
start_n <='1';
key_1<='1'; --按键1
key_2<='1'; --按键2
key_3<='1'; --按键3
key_4<='1'; --按键4
WAIT FOR 100 ns;
rst_n<='1';
WAIT FOR 1000 ns;
start_n <='0';
WAIT FOR 1000 ns;
start_n <='1';
WAIT FOR 50000 ns;
key_1<='0'; --按键1 提前抢答
WAIT FOR 100 ns;
key_1<='1'; --按键1
WAIT FOR 50000 ns;
rst_n<='0';
WAIT FOR 100 ns;
rst_n<='1';
WAIT FOR 1000 ns;
start_n <='0';
WAIT FOR 1000 ns;
start_n <='1';
WAIT FOR 150000 ns;
key_3<='0'; --按键3
WAIT FOR 100 ns;
key_3<='1'; --按键3
WAIT FOR 5000 ns;
WAIT FOR 5000 ns;
key_4<='0'; --按键4
WAIT FOR 100 ns;
key_4<='1'; --按键4
WAIT FOR 5000 ns;
WAIT;
END PROCESS init;
always : PROCESS
BEGIN
clk<='0';
WAIT FOR 10 ns;
clk<='1';
WAIT FOR 10 ns;
END PROCESS always;
END qiangdaqi_arch;