FPGA简单抢答器的实现

开发环境

AX301黑金开发版,编译软件quartus

主要功能

第一个文件
主要功能:
1.被动
正向计时,每5秒进行一次蜂鸣
2.主动
KEY2和KEY3同时按下,开始计时
KEY1 KEY2 KEY3分别按下对应LED亮起 且他人的灯不能再点亮,同时计时暂停
RESET重置LED 数码管

第二个文件
1.KEY2和KEY3同时按下,开始9秒倒计时,点亮LED0
2.KEY1 KEY2 KEY3开始作答,一人答题后其他人不可作答
3.如果LED0未亮,有人作答,蜂鸣器响
4.RESET键 一切重置

基本原理

1.按键消抖

问题描述

一个按键按下的理论状态是,立马发生电位变化,瞬间由最高点到底最低点,但实际上不可能实现,而是有略微抖动的变换.
在这里插入图片描述
在这里插入图片描述
实验中设计了一个计数器,当按键输入有变化时,
计时器清零,否则就累加,直到加到一个预定值(例如 10ms),就认为按键稳定,输出按键值,
这样就得到以后没有抖动的按键值。

代码展示

always @(posedge clk  or negedge rst_n)
    if (!rst_n) key_rst <= 1'b1;
    else key_rst <= sw3_n&sw2_n&sw1_n;
 
reg key_rst_r;       //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
 
always @ ( posedge clk  or negedge rst_n )
    if (!rst_n) key_rst_r <= 1'b1;
    else key_rst_r <= key_rst;
   
//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期 
wire key_an = key_rst_r & (~key_rst);
reg[19:0]  cnt;	//计数寄存器
 
always @ (posedge clk  or negedge rst_n)
    if (!rst_n) cnt <= 20'd0;	//异步复位
	else if(key_an) cnt <=20'd0;
    else cnt <= cnt + 1'b1;
  
reg[2:0] low_sw;
 
always @(posedge clk  or negedge rst_n)
    if (!rst_n) low_sw <= 3'b111;
    else if (cnt == 20'hfffff) 	//满20ms,将按键值锁存到寄存器low_sw中	 cnt == 20'hfffff
      low_sw <= {sw3_n,sw2_n,sw1_n};

reg  [2:0] low_sw_r;       //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
always @ ( posedge clk  or negedge rst_n )
    if (!rst_n) low_sw_r <= 3'b111;
    else low_sw_r <= low_sw;
//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期 
wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
reg d1;
reg d2;
reg d3;
always @ (posedge clk or negedge rst_n)
    if (!rst_n) begin
        d1 <= 1'b0;
        d2 <= 1'b0;
        d3 <= 1'b0;
      end
    else begin		//某个按键值变化时,LED将做亮灭翻转
        if ( led_ctrl[0]&led_d2==1'b0&led_d3==1'b0 ) d1 <= ~d1;	
        if ( led_ctrl[1]&led_d1==1'b0&led_d3==1'b0 ) d2 <= ~d2;
        if ( led_ctrl[2]&led_d1==1'b0&led_d2==1'b0 ) d3 <= ~d3;
      end
assign led_d1 = d1 ? 1'b1 : 1'b0;		//LED翻转输出
assign led_d2 = d2 ? 1'b1 : 1'b0;
assign led_d3 = d3 ? 1'b1 : 1'b0;		

2.6位数码管显示

使用方法

  1. 电路用 PNP 管来反向驱动并且控制列扫描信号(SEL0_T~SEL5_T)来选择哪个数码管。而且所有的 6 个数码管的“段选信号”(LEDA … LEDH)都共用驱动引脚(LED_A~LEDH)。数码管的所有驱动信号都是“低电平有效”。
  2. 单个数码管可以采用静态显示方式,如图所示,数码管被分成 a、b、c、d、e、f、g 和小数点,每段可以单独控制亮灭,通过点亮不同的段显示不同的数字和字符。
  3. 对于多位数码管,利用视觉暂留原理,快速交替显示,让眼睛看上去是多个数码管同时显示的。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

代码展示

译码模块
always@(*)
begin
	case(bin_data)
		4'd0:seg_data <= 7'b100_0000;
		4'd1:seg_data <= 7'b111_1001;
		4'd2:seg_data <= 7'b010_0100;
		4'd3:seg_data <= 7'b011_0000;
		… … … …
		default:seg_data <= 7'b111_1111;
	endcase
end
endmodule
//主要为了将二进制信号转化为段控制信号

在这里插入图片描述

计数器
always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
	begin 
		scan_timer <= 32'd0;
		scan_sel <= 4'd0;
		end
	else if(scan_timer >= SCAN_COUNT)
	begin 
		scan_timer <= 32'd0;
		if(scan_sel == 4'd5)
			scan_sel <= 4'd0;
		else
			scan_sel <= scan_sel + 4'd1;
			end
	else
		begin 
			scan_timer <= scan_timer + 32'd1; 
			end
end
always@(posedge clk or negedge rst_n)
begin if(rst_n == 1'b0)
	begin 
		seg_sel <= 6'b111111;
		seg_data <= 8'hff;
		end
	else
	begin 
		case(scan_sel)
			4'd0:
			begin seg_sel <= 6'b11_1110;
				seg_data <= seg_data_0; 
				end
			… …		
		endcase
	end
end

在这里插入图片描述

模十计数器
always@(posedge clk or negedge rst_n) 
begin
    if(rst_n==0)
    begin
        data <= 4'd0;
        t <= 1'd0;
    end
    else if(clr)
    begin
        data <= 4'd0;
        t <= 1'd0;      
    end
        else if(en&led_d1==led_d2==led_d3==0)
    begin
        if(data==4'd9)
        begin
            t<= 1'b1;    //Counter to 9 to generate carry
            data <= 4'd0;
            end//Counter to 9 reset
        else
        begin
            t <= 1'b0;
            data <= data + 4'd1;
            end
    end
    else
        t <= 1'b0;
end

在这里插入图片描述

5秒一蜂鸣
always @(posedge clk)
	if(data==4'd5)
		 buzzer <= 1'b0;
	else if(data==4'd0)
		 buzzer <= 1'b0;
	else
		 buzzer <= 1'b1;

问题总结

  1. 同一信号不能在两个always里改变,但是可以在两个always里分别用作条件
  2. output从模块调用到主程序时,模块中要设置成reg形式;
  3. 逻辑层面要设计好,比如倒计时;比如信号到底在哪里修改;比如灵活性,简洁性
  4. 空的引脚可以不用分配,默认低电平;运行前一定要把电压设置好,还有芯片型号

给读者的问题

1.设置消抖的锁存器的时间,应该设置多少秒合适?
2.数码管交替的频率设置为多少较为合适?
3:请问单个数码管有几个控制段?是否全部可以同时点亮
4:两个always里,可以同时用一个信号作为判断条件么?

1.20ms左右,可以稍微加长;
2.1ms,实际20ms以内就行,太慢会闪烁,太快会导致亮度不够
3.8个,包含小数点;不可以同时点亮,6个通用一个电位
4.可以,只是不能在两处改变

整体代码(觉得麻烦可以直接在我资源里下载)

第一个文件

module seg_test(
	input   			clk,	//主时钟信号,50MHz
	input   			rst_n,	//复位信号,低有效
	input   		 	sw1_n,sw2_n,sw3_n, 	//三个独立按键,低表示按下
	output 	 	 	led_d0=0,led_d1,led_d2,led_d3,	//发光二极管,分别由按键控制
	output 			buzzer,
   output
  • 23
    点赞
  • 129
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
基于FPGA抢答器是一种利用现场可编程门阵列(Field-Programmable Gate Array,FPGA)技术设计的抢答设备。 FPGA是一种灵活可编程的硬件平台,它可以重新配置电路结构和功能,使得基于它的抢答器可以灵活适应不同的需求。该抢答器系统主要由FPGA芯片、按键、显示屏和其他外设组成。 首先,按键是抢答器的核心组成部分,由多个按键组成,每个按键对应一个参赛者。当主持人提出问题时,参赛者可以通过按下相应的按键进行抢答,FPGA芯片会通过扫描按键状态来获取参赛者的答题顺序。 然后,FPGA芯片会记录并处理按键输入信号,确定抢答顺序。它可以利用FPGA的并行处理能力,实时地对多个参赛者的抢答进行监测和计算。一旦有参赛者按下按键,FPGA芯片会立即停止扫描其他按键,并记录该参赛者的抢答时间。 最后,抢答器系统会通过显示屏将抢答顺序显示给观众和主持人。在显示屏上,可以实时显示抢答者的编号和抢答时间,帮助主持人了解抢答情况并进行评判。 基于FPGA抢答器具有实时性、高精度和灵活性的特点。它可以在短时间内准确记录多个参赛者的抢答顺序,避免了传统抢答器可能出现的延迟和误判问题。同时,由于FPGA的可编程性,抢答器可以根据需要进行定制和优化,满足不同比赛场景的要求。 总的来说,基于FPGA抢答器是一种高效、准确的抢答设备,可以广泛应用于各类抢答竞赛、知识竞赛和培训活动,提升了抢答活动的公平性和娱乐性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值