抢答器设计
软件:PC、Quartus Prime 18.1、Modelsim 10.5b
硬件:Altera FPGA开发板(EP4CE6E22F17C8)
基于开发板上的8位8段数码管和4个机械按键,制作一个抢答器,相关要求如下:
1、 设置四个按键,其中三位选手A、B、C,主持人0;
2、 主持人具有清除所有状态权限
3、 每次抢答开始后,选手需要在10S做出选择,否测视为放弃,一旦某位选手按下按键后,另外两名选手按键将失效
4、 如果没有选手抢答,数码管显示10s倒计时,计时结束时,LED不停闪烁;同时,所有选手按键失效,直到主持人重新开始
5、 最左边显示显示倒计时,低三位从左至右分别表示选手ABC,当某位选手抢答后,将显示对应字符(A or B or C),同时倒计时暂停,直至主持人按下后,所有状态恢复,开启新一轮抢答。
根据开发板的原理图,可得到以下资料
数码管:本质上为一组发光二极管按照一定顺序排列而成,其显示原理与LED无异。


根据硬件原理图所示,发光二极管,所有的阳极都接通3.3V的正电压,也即—高电平,所以如果我们想要
发光二极管导通的话,需要在阴极接通低电平,就可以让LED亮起来。
根据系统要求,可以得到以下框架分布

根据系统构建,可得到以下模块

| 信号名 | 端口类型 | 数据位宽 | 信号说明 |
|---|---|---|---|
| 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﹕adolph1354238998@gmail.com
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;
always@(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
always@(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
always@(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
always@(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;
always@(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
本模块较为简单,此处不做仿真验证,如有兴趣可自行验证
数码管区驱动在之前的基础上有所改动,大家自行理解
/*================================================*\
Filename ﹕seg_driver.v
Author ﹕Adolph
Description ﹕对输入的数据译码,并驱动数码管显示对应数据
Called by ﹕responder.v
Revision History ﹕ 2022-5-30 14:27:22
Revision 1.0
Email﹕adolph1354238998@gmail.com
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;
//描述位选信号切换
//描述刷新计数器
always@(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
always@(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
//段选信号描述
always@(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
always@(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
设计文件
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
always@(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 输出
always@(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
该模块在之前有设计过,这里不做过赘述,可参考抖 verilog实现按键消
`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;
always@(*)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

顶层文件在此不作讲解,根据下列RTL视图,相信读者可以很轻易的完成相应代码设计
RTL视图

具体实现效果如预期所述,请大家自行探索
本设计实现了基本的功能
在设计过程中,由于位宽不匹配(quartus不会报错,只会报警告),导致程序运行效果不正确,多次检错才确定具体原因
故,告诫大家,在进行信号描述的时候,一定要将位宽进行匹配
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:
我正在尝试创建密码规则来设计可恢复的密码更改。我通过passwords_controller.rb做了一个父类(superclass),但我需要在应用规则之前检查用户角色,但我所拥有的只是reset_password_token。 最佳答案 假设您的模型是用户:User.with_reset_password_token(your_token_here)Source 关于ruby-on-rails-设计通过reset_password_token获取用户,我们在StackOverflow
我已经使用Apartment设置了一个Rails5应用程序(1.2.0)和Devise(4.2.0)。由于某些DDNS问题,应用只能在app.myapp.com下访问(请注意子域app)。myapp.com重定向到app.myapp.com。我的用例是每个注册该应用的用户(租户)都应该通过他们的子域(例如tenant.myapp.com)访问他们的特定数据。用户不应限定在其子域内。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题开始的
我在关注RyanbatesRailsCast的devise和omniauth(第235集-devise-and-omniauth-revised)。当我尝试使用Twitter登录时,标题中不断出现错误。defself.new_with_session(params,session)ifsession["devise.user_attributes"]new(session["devise.user_attributes"],without_protection:true)do|user|user.attributes=paramsuser.valid?end完整跟踪:C:/Ruby20
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>