当前位置:网站首页>verilog设计抢答器【附源码】
verilog设计抢答器【附源码】
2022-07-07 09:02:00 【青柠Miya】
抢答器设计
1、实验平台
软件:PC、Quartus Prime 18.1、Modelsim 10.5b
硬件:Altera FPGA开发板(EP4CE6E22F17C8)
2、实验目的
- 1、掌握数码管动态刷新原理
- 2、逻辑练习
2.1、实验内容
基于开发板上的8位8段数码管和4个机械按键,制作一个抢答器,相关要求如下:
1、 设置四个按键,其中三位选手A、B、C,主持人0;
2、 主持人具有清除所有状态权限
3、 每次抢答开始后,选手需要在10S做出选择,否测视为放弃,一旦某位选手按下按键后,另外两名选手按键将失效
4、 如果没有选手抢答,数码管显示10s倒计时,计时结束时,LED不停闪烁;同时,所有选手按键失效,直到主持人重新开始
5、 最左边显示显示倒计时,低三位从左至右分别表示选手ABC,当某位选手抢答后,将显示对应字符(A or B or C),同时倒计时暂停,直至主持人按下后,所有状态恢复,开启新一轮抢答。
3、实验流程
3.1、实验原理
根据开发板的原理图,可得到以下资料
数码管:本质上为一组发光二极管按照一定顺序排列而成,其显示原理与LED无异。
根据硬件原理图所示,发光二极管,所有的阳极都接通3.3V的正电压,也即—高电平,所以如果我们想要
发光二极管导通的话,需要在阴极接通低电平,就可以让LED亮起来。
3.2、系统架构
根据系统要求,可以得到以下框架分布
3.3、子功能模块设计
根据系统构建,可得到以下模块
3.3.1、中央控制模块
模块框图
信号定义
信号名 | 端口类型 | 数据位宽 | 信号说明 |
---|---|---|---|
Clk | i | 1 | 输入时钟信号,50MHz |
Rst_n | i | 1 | 输入复位信号,低电平有效 |
key_A | i | 1 | 选手A按键 |
key_B | i | 1 | 选手B按键 |
key_C | i | 1 | 选手C按键 |
key_0 | i | 1 | 主持人按键 |
Data_time | O | 16 | 10s倒计时数据 |
Led_en | O | 1 | 倒计时结束,使能LED闪烁 |
设计文件
/*================================================*\ Filename ﹕ctrl_mode.v Author ﹕Adolph Description ﹕中控模块,指令解析,数据显示控制 Called by ﹕responder.v Revision History ﹕ 2022-6-20 15:20:43 Revision 1.0 Email﹕[email protected] Company﹕ \*================================================*/
module ctrl_mode(
input clk ,
input rst_n ,
input [3:0] key_ctrl, //按键消抖信号
output [3:0] data ,
output reg [3:0] key_sta , //按键状态信号
output reg led_en
);
//parameter declarations
parameter TIME_S = 26'd50_000_000;
//internal reg / wire signals
reg [25:0] cnt_1s ;
wire add_1s ;
wire end_1s ;
reg latch_log;
reg [3:0] cnt_delay;//显示9-0
wire add_delay;
wire end_delay;
assign data = cnt_delay;
// assign led_en = end_delay;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
led_en <= 1'b0;
end
else if(key_ctrl[0])begin
led_en <= 1'b0;
end
else if(end_delay)begin
led_en <= 1'b1;
end
else begin
led_en <= led_en;
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_sta <= 4'b0000;
end
else if(key_ctrl[0])begin //主持人按键按下之后
key_sta <= 4'b0001;
end
else if(latch_log)begin
key_sta <= key_sta;
end
else begin
case(key_ctrl)
4'b0010:key_sta[1] <= 1'b1;
4'b0100:key_sta[2] <= 1'b1;
4'b1000:key_sta[3] <= 1'b1;
default: ;
endcase
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
latch_log <= 1'b1; //初始上电后,锁定生效
end
else if(key_ctrl[0])begin //主持人按下,锁定失效,选手按下有效
latch_log <= 1'b0;
end
else if(key_ctrl[1] || key_ctrl[2] || key_ctrl[3] || end_delay)begin //任一选手按下后,锁定生效;倒计时结束,同样不允许选手按键
latch_log <= 1'b1;
end
else begin
latch_log <= latch_log;
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1s <= 'd0;
end
else if(add_1s)begin
if(end_1s)begin
cnt_1s <= 'd0;
end
else begin
cnt_1s <= cnt_1s + 26'd1;
end
end
else begin
cnt_1s <= cnt_1s;
end
end
assign add_1s = key_sta == 4'b0001;
assign end_1s = add_1s && cnt_1s >= TIME_S - 'd1;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_delay <= 'd10;
end
else if(key_ctrl[0])begin
cnt_delay <= 'd10;
end
else if(add_delay)begin
if(end_delay)begin
cnt_delay <= cnt_delay;
end
else begin
cnt_delay <= cnt_delay - 4'd1;
end
end
else begin
cnt_delay <= cnt_delay;
end
end
assign add_delay = end_1s;
assign end_delay = add_delay && cnt_delay == 'd1 - 'd1;
endmodule
本模块较为简单,此处不做仿真验证,如有兴趣可自行验证
3.3.2、数码管驱动模块
数码管区驱动在之前的基础上有所改动,大家自行理解
设计文件
/*================================================*\ Filename ﹕seg_driver.v Author ﹕Adolph Description ﹕对输入的数据译码,并驱动数码管显示对应数据 Called by ﹕responder.v Revision History ﹕ 2022-5-30 14:27:22 Revision 1.0 Email﹕[email protected] Company﹕ \*================================================*/
module seg_driver(
input clk ,
input rst_n ,
input [03:0] key_ctrl,
input [31:0] dis_data,//倒计时数据
output reg [07:0] dig_sel ,
output reg [07:0] dig_seg
);
//wire [31:0]dis_data;
// assign dig_seg = 8'd0;
// assign dig_sel = 1'b0;
localparam
NUM_0 = 8'hC0,
NUM_1 = 8'hF9,
NUM_2 = 8'hA4,
NUM_3 = 8'hB0,
NUM_4 = 8'h99,
NUM_5 = 8'h92,
NUM_6 = 8'h82,
NUM_7 = 8'hF8,
NUM_8 = 8'h80,
NUM_9 = 8'h90,
NUM_A = 8'h88,
NUM_B = 8'h83,
NUM_C = 8'hC6,
NUM_D = 8'hA1,
NUM_E = 8'h86,
NUM_F = 8'h8E,
LIT_ALL = 8'h00,
BLC_ALL = 8'hFF;
parameter CNT_REF = 25'd1000;
reg [9:0] cnt_20us; //20us计数器
reg [4:0] data_tmp; //用于取出不同位选的显示数据
// assign dis_data = 32'hABCD_4413;
//描述位选信号切换
//描述刷新计数器
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_20us <= 10'd0;
end
else if(cnt_20us >= CNT_REF - 10'd1)begin
cnt_20us <= 10'd0;
end
else begin
cnt_20us <= cnt_20us + 10'd1;
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
dig_sel <= 8'hfe;//8'b1111_1110
end
else if(cnt_20us >= CNT_REF - 10'd1)begin
dig_sel <= {
dig_sel[6:0],dig_sel[7]};
end
else begin
dig_sel <= dig_sel;
end
end
//段选信号描述
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_tmp <= 5'd0;
end
else if(key_ctrl[0])begin
data_tmp <= 5'h10;
end
else begin
case(dig_sel)
8'b1111_1110: begin
if(key_ctrl[3])
data_tmp <= 5'hc;
else
data_tmp <= 5'h10;
end
8'b1111_1101: begin
if(key_ctrl[2])
data_tmp <= 5'hb;
else
data_tmp <= 5'h10;
end
8'b1111_1011: begin
if(key_ctrl[1])
data_tmp <= 5'ha;
else
data_tmp <= 5'h10;
end
8'b1111_0111:data_tmp <= 5'h10;
8'b1110_1111:data_tmp <= 5'h10;
8'b1101_1111:data_tmp <= 5'h10;
8'b1011_1111:data_tmp <= 5'h10;
8'b0111_1111:data_tmp <= dis_data[3-:4];
default: data_tmp <= 5'hF;
endcase
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
dig_seg <= LIT_ALL;
end
else begin
case(data_tmp)
5'h0 : dig_seg <= NUM_0;
5'h1 : dig_seg <= NUM_1;
5'h2 : dig_seg <= NUM_2;
5'h3 : dig_seg <= NUM_3;
5'h4 : dig_seg <= NUM_4;
5'h5 : dig_seg <= NUM_5;
5'h6 : dig_seg <= NUM_6;
5'h7 : dig_seg <= NUM_7;
5'h8 : dig_seg <= NUM_8;
5'h9 : dig_seg <= NUM_9;
5'hA : dig_seg <= NUM_A;
5'hB : dig_seg <= NUM_B;
5'hC : dig_seg <= NUM_C;
5'hD : dig_seg <= NUM_D;
5'hE : dig_seg <= NUM_E;
5'hF : dig_seg <= NUM_F;
5'h10: dig_seg <= BLC_ALL;
default:dig_seg <= LIT_ALL;
endcase
end
end
endmodule
3.3.3 LED驱动模块
设计文件
module led_water(
input clk ,//50MHz
input rst_n ,//low valid
input blink_en,//闪烁使能信号
output reg [7:0] led_o
);
//参数定义
parameter CNT_MAX = 25'd500_0000;
//信号定义
reg [24:0] cnt;//500ms计数器,计数最大值 2500_0000,
//计时 0-500ms
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 25'd0;
else if(blink_en)begin
if(cnt >= CNT_MAX - 25'd1)
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
end
else
cnt <= 25'd0;
end
//led 输出
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)
led_o <= 8'b0000_0000; //all light
else if(blink_en)begin
if(cnt >= CNT_MAX - 25'd1)
led_o <= ~led_o;
else
led_o <= led_o; //s
end
else begin
led_o <= 8'b0000_0000;
end
end
endmodule
3.3.4、按键消抖模块
该模块在之前有设计过,这里不做过赘述,可参考抖 verilog实现按键消
3.4仿真验证
`timescale 1ns/1ns //仿真系统时间尺度定义
`define clk_period 20 //时钟周期参数定义
module tb_responder();
//激励信号定义
reg Clk ;
reg Rst_n ;
reg [3:00] key_in ; //
//响应信号定义
wire [7:0] dig_sel ;
wire [7:0] dig_seg ;
wire [7:0] led_o ;
defparam responder.DELAY_TIME = 200;
defparam responder.ctrl_mode.TIME_S = 200;
defparam responder.seg_driver.CNT_REF = 100;
reg [55:00] ASCILL; //
localparam
NUM_0 = 8'hC0,
NUM_1 = 8'hF9,
NUM_2 = 8'hA4,
NUM_3 = 8'hB0,
NUM_4 = 8'h99,
NUM_5 = 8'h92,
NUM_6 = 8'h82,
NUM_7 = 8'hF8,
NUM_8 = 8'h80,
NUM_9 = 8'h90,
NUM_A = 8'h88,
NUM_B = 8'h83,
NUM_C = 8'hC6,
NUM_D = 8'hA1,
NUM_E = 8'h86,
NUM_F = 8'h8E,
LIT_ALL = 8'h00,
BLC_ALL = 8'hFF;
[email protected](*)begin
case(responder.seg_driver.dig_seg)
NUM_0 : ASCILL = "NUM_0 ";
NUM_1 : ASCILL = "NUM_1 ";
NUM_2 : ASCILL = "NUM_2 ";
NUM_3 : ASCILL = "NUM_3 ";
NUM_4 : ASCILL = "NUM_4 ";
NUM_5 : ASCILL = "NUM_5 ";
NUM_6 : ASCILL = "NUM_6 ";
NUM_7 : ASCILL = "NUM_7 ";
NUM_8 : ASCILL = "NUM_8 ";
NUM_9 : ASCILL = "NUM_9 ";
NUM_A : ASCILL = "NUM_A ";
NUM_B : ASCILL = "NUM_B ";
NUM_C : ASCILL = "NUM_C ";
NUM_D : ASCILL = "NUM_D ";
NUM_E : ASCILL = "NUM_E ";
NUM_F : ASCILL = "NUM_F ";
LIT_ALL : ASCILL = "LIT_ALL";
BLC_ALL : ASCILL = "BLC_ALL";
default : ASCILL = "LIT_ALL";
endcase
end
//实例化
responder responder(
/*input */.clk (Clk ),
/*input */.rst_n (Rst_n ),
/*input [3:0] */.key_in (key_in ), //按键消抖信号
/*output [7:0] */.dig_sel (dig_sel),
/*output [7:0] */.dig_seg (dig_seg),
/*output [7:0] */.led_o (led_o )
);
//产生时钟
initial Clk = 1'b0;
always #(`clk_period / 2) Clk = ~Clk;
//产生激励
initial begin
Rst_n = 1'b0;
key_in = 4'b1111;
#(`clk_period * 20 + 3);
Rst_n = 1'b1;
#(`clk_period * 20);
press_key0;
#(`clk_period * 2000);
press_key3;
$stop(2);
end
reg [15:0] my_rand;
task press_key0 ;
begin
//前抖动
repeat(10)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[0] = ~key_in[0];
end
key_in[0] = 1'b0;
#(400 * `clk_period); //21ms > 20ms
//后抖动
repeat(11)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[0] = ~key_in[0];
end
key_in[0] = 1'b1;
#(1000 * `clk_period); //21ms > 20ms
end
endtask
task press_key1 ;
begin
//前抖动
repeat(19)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[1] = ~key_in[1];
end
key_in[1] = 1'b0;
#(400 * `clk_period); //21ms > 20ms
//后抖动
repeat(10)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[1] = ~key_in[1];
end
key_in[1] = 1'b1;
#(1000 * `clk_period); //21ms > 20ms
end
endtask
task press_key2 ;
begin
//前抖动
repeat(13)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[2] = ~key_in[2];
end
key_in[2] = 1'b0;
#(400 * `clk_period); //21ms > 20ms
//后抖动
repeat(10)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[2] = ~key_in[2];
end
key_in[2] = 1'b1;
#(1000 * `clk_period); //21ms > 20ms
end
endtask
task press_key3 ;
begin
//前抖动
repeat(15)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[3] = ~key_in[3];
end
key_in[3] = 1'b0;
#(400 * `clk_period); //21ms > 20ms
//后抖动
repeat(11)begin
my_rand = {
$random} % 50 ;
#my_rand key_in[3] = ~key_in[3];
end
key_in[3] = 1'b1;
#(1000 * `clk_period); //21ms > 20ms
end
endtask
endmodule
3.4、板级验证
3.4.1、顶层文件
顶层文件在此不作讲解,根据下列RTL视图,相信读者可以很轻易的完成相应代码设计
RTL视图
具体实现效果如预期所述,请大家自行探索
4、总结
本设计实现了基本的功能
在设计过程中,由于位宽不匹配(quartus不会报错,只会报警告),导致程序运行效果不正确,多次检错才确定具体原因
故,告诫大家,在进行信号描述的时候,一定要将位宽进行匹配
边栏推荐
- 打算参加安全方面工作,信息安全工程师怎么样,软考考试需要怎么准备?
- The difference between monotonicity constraint and anti monotonicity constraint
- When do you usually get grades in the soft exam? Online pedaling?
- SQL Server 知识汇集9 : 修改数据
- 從色情直播到直播電商
- 高级软考(网络规划设计师)该如何备考?
- Records on the use of easyflash v3.3
- Bookmarking - common website navigation for programmers
- The seventh training assignment
- [untitled]
猜你喜欢
IDEA快捷键大全
【推薦系統 01】Rechub
[actual combat] transformer architecture of the major medical segmentation challenges on the list --nnformer
"Dream Cup" 2017 Jiangsu information and future primary school summer camp it expert PK program design questions
想考中级软考,一般需要多少复习时间?
[C #] the solution of WinForm operation zoom (blur)
MPX plug-in
ADB utility commands (network package, log, tuning related)
[untitled]
Simple and easy to modify spring frame components
随机推荐
Monai version has been updated to 0.9. See what new functions it has
從色情直播到直播電商
"Dream Cup" 2017 Jiangsu information and future primary school summer camp it expert PK program design questions
【机器学习 03】拉格朗日乘子法
Vscode 尝试在目标目录创建文件时发生一个错误:拒绝访问【已解决】
Mysql的json格式查询
【安装系统】U盘安装系统教程,使用UltraISO制作U盘启动盘
Bookmarking - common website navigation for programmers
Long list performance optimization scheme memo
JS implementation chain call
Mpx 插件
Interprocess communication (IPC)
Project ERROR: Unknown module(s) in QT: core gui
高级软考(网络规划设计师)该如何备考?
[OneNote] can't connect to the network and can't sync the problem
A case of compiling QT file qmake compiling script
mif 文件格式记录
A simple example of delegate usage
Ping tool ICMP message learning
Static semantic check of clang tidy in cicd