基于fpga的数字式竞赛抢答器(使用Quartus原理图设计)
1. 功能需求
要求具备第一信号鉴别和锁存功能,使除第一抢答者外的按钮不起作用;设置一个主持人“复位”按钮,主持人复位后,开始抢答,第一信号鉴别锁存电路得到信号后,用指示灯显示抢答组别;设置犯规电路,对提前抢答和超时答题的组别进行示警,并由组别显示电路显示出犯规组别;设置一个计分电路,每组开始预置10分,由主持人记分,答对一次加1分,答错一次减1分。
2. 设计思路
此设计问题可分为第一信号鉴别锁存模块、答题计时模块、计分电路模块和扫描显示模块四部分。第一信号鉴别锁存模块的关键是准确判断出第一抢答者并将其锁存,在得到第一信号后将输入端封锁,使其他组的抢答信号无效,可以用触发器或锁存器实现。设置抢答按钮K1、K2、K3、K4,主持人复位信号reset。
当reset=0时,第一信号鉴别锁存电路、答题计时电路复位,此状态下,若有抢答按钮按下,鸣笛示警并显示犯规组别;当reset=1时,开始抢答,由第一信号鉴别锁存电路形成第一抢答信号.进行组别显示,控制扬声器发出音响,并启动答题计时电路,若计时时间到主持人复位信号还没有按下,则由指示灯闪烁示警。
计分电路是一个相对独立的模块,采用十进制加/减计数器、数码管数码扫描显示,设置复位信号resetl、加分信号up、减分信号down,当resetl=0时,所有得分回到起始分(10分),且加分、减分信号无效;当reset1=1时,由第一信号鉴别锁存电路的输出信号选择进行加减分的组别,每按一次up,第一抢答组加一分;每按一次down,第一抢答组组减一分。
3. 实现过程
3.1 第一信号鉴别锁存模块 + 犯规电路
(1) 使用器件
74175,带公共时钟和复位四D触发器
(2) 原理
a. 比赛开始前,主持人复位按钮RET=0,四个D触发器复位,此时输出Q[1]–Q[4]为0,QN[1]–QN[4]为1,QN[1]–QN[4]经过与门后输出D为1,时钟CLK所经过的与门(AND2)打开。
犯规电路中RET经过非门和抢答信号相与,输出控制相应组别的犯规指示灯及报警。当RET=0时,若有选手抢答(假若为1号选手),A1=0,A1N=1,与门输出结果QX[1]=1。
b. 比赛开始时,主持人复位按钮RET=1,四个D触发器正常工作。若此时有选手抢答(假设是1号选手),A1=0(抢答按钮按下为0),经过非门后D触发器的输入端1D=1,根据D触发器的特性可知,输出1Q=1、1QN=0,与门(AND4)的输出D=0,此时CLK所经过的与门(AND2)关闭,输出为0,所以D触发器的时钟一直为0,直到下次复位(RET=0)时恢复。由于74175中的D触发器为上升沿触发,所以当时钟为低电平时,D触发器不工作,保持上次的输出,直到下一个上升沿到来。如此便可实现对一次抢答过程中的第一信号进行鉴别和锁存。
(3) 模块化
输入:
-
A1–A4分配四个按键开关(按下为0,不按为1)
-
RET分配一个拨码开关
-
CLKH为50MHz时钟源
输出:
-
Q[1]–Q[4]分配四个LED,显示抢答结果
-
QX[1]–QX[4]分配四个LED,显示提前抢答导致犯规的组别
3.2 答题计时电路
(1) 使用器件
74192,可预置的十进制同步加 / 减计数器
- DN为接减计数脉冲,UP接加计数脉冲
- LDN置数,CLR异步复位
- CON为进位输出,低电平有效(即产生进位时CON输出低电平);BON为借位输出,低电平有效(即产生借位时BON输出低电平)
(2) 原理
第一片作为低位,第二片作为高位。先给预置数60,即第一片的A、B、C、D接地;第二片的A、D接地,B、C接高电平。将第一片的借位输出BON作为第二片的减计数脉冲DN,同时将分频后得到的1Hz时钟CLK作为第一片的减计数脉冲DN。如此一来,每当第一片减到0时,第二片减1,这样就实现了60秒倒计时的功能。
主持人复位信号与两片的置数端LDN相连,每当复位时(RET=0),计数器恢复初始值60。
将第二片的借位输出作为报警信号,当计数器值为00时,产生报警。
为了使计数器值为00时停止,将第二片的借位输出反向后与两片的异步复位端相连。
(3) 模块化
- 图中JSQ1KHZ为分频模块,目的时将50MHz时钟脉冲转换为1Hz,使计数器每次计数时间为1s。
- 将四个QN信号通过与非门后和复位信号RET相与,输出作为计数器的复位信号,目的是使计数器在比赛开始后(RET=1)有选手抢答时(QN=0)开始计数。
输入:
- CLKH为50MHz时钟源
- RET为主持人复位信号
- QN为第一信号鉴别锁存模块的输出(产生抢答信号时QN=0)
输出:
- CH为计数器高四位输出(十位),为BCD码
- CL为计数器低四位输出(个位),为BCD码
- alarm为报警信号,接报警LED
3.3 计分电路
(1) 使用器件
74192,可预置的十进制同步加 / 减计数器
(2) 原理
第一片74192作为低位,第二片作为高位。预置数10,即第一片A、B、C、D接地,第二片B、C、D接地,A接高电平。将加减分信号分别作为第一片的加减计数脉冲。同时第一片的进位输出作为第二片的加计数脉冲,第一片的借位输出作为第二片的减计数脉冲。如此一来,加减分信号控制第一片74192加计数或者减计数,当第一片产生进位或借位时,控制第二片加减,这样就实现了由加减分信号控制的十进制可逆计数器。
两片74192的置数端同时与RETscore相连,当RETscore=0时,计分电路恢复初始值10。
KeyPress为按键消抖模块,由按键产生的含抖动的加减分信号经过该模块输出一个稳定的状态信号。
(3) 模块化
图中加减分信号与Q相与,输出分别接各自的计分电路,目的是实现对各自分数的单独控制,即加减分信号只对抢答者的计分电路生效
输入:
-
R为计分电路的复位信号,R=0时,每个人的分数重置,恢复到初始值10
-
up为加分信号,接按键
-
down为减分信号,接按键
-
CLKH为50MHz时钟源
输出:
- H1、H2、H3、H4分别为四人得分的高四位输出(BCD码)
- L1、L2、L3、L4分别为四人得分的低四位输出(BCD码)
3.4 数码管扫描显示原理介绍(仅限博主所用实验箱)— 补充内容
当用七段显示器显示的位数较多时,例如显示八位十进制数,为了节省硬件开支,常用扫描显示方法,即对显示器进行循环扫描,分时驱动。该电路由五个部分组成:四位二进制计数器74161,3-8 译码器74138,四位八选一数据选择器,BCD-七段显示译码器7448 和八位七段显示器等,原理图如下:
利用人眼的视觉惯性,扫描频率应大于50HZ,根据计数器的分频关系,实际扫描频率CLK应大于200HZ。
3.5 数码管扫描显示模块
(1) 使用器件
-
74161,可预置四位二进制异步清除计数器
-
mux8,四位八选一数据选择器
-
7448,BCD—7段显示译码器
(2) 原理
计数器74161在扫描时钟CLKL作用下循环输出000–111(SEL[2]、SEL[1]、SEL[0]),将其作为3-8译码器的输入,译码器输出位控信号MS1–MS8,控制八位数码管开关。
四位八选一数据选择器根据数据选择信号SEL[2]、SEL[1]、SEL[0]的数值从八路输入数据中选择一路数据(一位BCD 码)送给BCD-七段显示译码器,通过BCD-七段显示译码器译成七段显示码,驱动七段数码管显示具体内容。在连续8 个时钟周期内,八个显示器轮流点亮一个时钟周期。只要输入连续时钟CLK,就能实现八个数码管扫描显示。利用人眼的视觉惯性,扫描频率应大于50HZ,根据计数器的分频关系,实际扫描频率CLK 应大于200HZ。
(3) 模块化
输入:
- 八路四位数据分别为四个计分电路的输出
- 扫描时钟CLKL为1MHz时钟源
- RN为控制所有数码管的工作状态,RN=0时,所有数码管都关闭
输出:
- MS1、MS2、MS3接内部的3-8译码器,控制8位数码管的通断,某一时刻只有一位数码管工作
- a、b、c、d、e、f、g与数码管的相应段相接,dp接地
4. 结果
5. 补充
- 博主所用实验箱引脚表:
- 实际功能区划分及硬件使用情况:
- 按键消抖模块KeyPress采用verilog语言设计,具体代码如下:
module KeyPress(
CLK,
nRST,
KEY_IN,
KEY_FLAG,
KEY_STATE
);
input CLK;
input nRST;
input KEY_IN;
output reg KEY_FLAG;
output reg KEY_STATE;
reg key_a, key_b;
reg en_cnt, cnt_full;
reg [3:0]state;
reg [19:0]cnt;
wire flag_H2L, flag_L2H;
localparam
Key_up = 4'b0001,
Filter_Up2Down = 4'b0010,
Key_down = 4'b0100,
Filter_Down2Up = 4'b1000;
//======判断按键输入信号跳变沿========//
always @(posedge CLK or negedge nRST)
if(!nRST)
begin
key_a <= 1'b0;
key_b <= 1'b0;
end
else
begin
key_a <= KEY_IN;
key_b <= key_a;
end
assign flag_H2L = key_b && (!key_a);
assign flag_L2H = (!key_b) && key_a;
//============计数使能模块==========//
always @(posedge CLK or negedge nRST)
if(!nRST)
cnt <= 1'b0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 1'b0;
//=============计数模块=============//
always @(posedge CLK or negedge nRST)
if(!nRST)
cnt_full <= 1'b0;
else if(cnt == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
//=============有限状态机============//
always @(posedge CLK or negedge nRST)
if(!nRST)
begin
en_cnt <= 1'b0;
state <= Key_up;
KEY_FLAG <= 1'b0;
KEY_STATE <= 1'b1;
end
else
case(state)
//保持没按
Key_up: begin
KEY_FLAG <= 1'b0;
if(flag_H2L) begin
state <= Filter_Up2Down;
en_cnt <= 1'b1;
end
else
state <= Key_up;
end
//正在向下按
Filter_Up2Down: begin
if(cnt_full) begin
en_cnt <= 1'b0;
state <= Key_down;
KEY_STATE <= 1'b0;
KEY_FLAG <= 1'b1;
end
else if(flag_L2H) begin
en_cnt <= 1'b0;
state <= Key_up;
end
else
state <= Filter_Up2Down;
end
//保持按下状态
Key_down: begin
KEY_FLAG <= 1'b0;
if(flag_L2H) begin
state <= Filter_Down2Up;
en_cnt <= 1'b1;
end
else
state <= Key_down;
end
//正在释放按键
Filter_Down2Up: begin
if(cnt_full) begin
en_cnt <= 1'b0;
state <= Key_up;
KEY_FLAG <= 1'b1;
KEY_STATE <= 1'b1;
end
else if(flag_H2L) begin
en_cnt <= 1'b0;
state <= Key_down;
end
else
state <= Filter_Down2Up;
end
//其他未定义状态
default: begin
en_cnt <= 1'b0;
state <= Key_up;
KEY_FLAG <= 1'b0;
KEY_STATE <= 1'b1;
end
endcase
endmodule