基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)

本篇文章参考了CSDN用户 ifreewolf_csdn,在这里深表感谢!!!

一个抢答器设计:

像C语言一样直接写一个main函数,我开始设法运用数电的知识,尝试着来我这个模块能不能一步到位,一镜到底!
(1) 重新审视问题,制定明确的规则:
抢答器的台数最终定为6台,
当主持人按下reset键抢答开始,倒计时20秒,20秒倒计时之后抢答视为超时发出报警,系统还会显示出超前抢答的台号,系统复位之后,再次按下开始抢答键,抢答开始,当一旦有一路按键按下,该路的抢答信号会将其他各路的抢答信号封锁响铃,显示牌上会显示相应的抢答台号
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第1张图片
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第2张图片
(2) 明确复位信号的作用,寄存器全部清0
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第3张图片
(3) 因为系统还要感知到有超前抢答的信号,我们就必须有一个寄存器变量是与start键一同开始赋值变化的,想到这里,引入一位寄存器变量come_on
在这里插入图片描述
(4) 输入抢答端有六个端口(rusher1~6),就像开关一样的效果,初态为0,一旦按下去就设为1,设为1之后不会自动再跳回0,仍需要手动输入(目前没有想到好的办法),同时因为系统还要感知到是否是超前抢答了,那就必须有另一个寄存器变量与按键信号rusher[]一同变化,我们设置为flag(1位寄存器变量)基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第4张图片

这个模块我们实际上有6个独立相似模块(因为我们有6个抢答按键)
(5) 关于计数模块:这部分相对复杂,首先需要感知到抢答开始信号开始计数,同时又要感知到正规抢答信号停止计数,如果是超前抢答,计数模块还不能发生变化,同时因为我们设置的是20秒倒计时,设置了一个5位的寄存器变量count_down用于倒计时
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第5张图片
因为我们flag的初值设的是0,只有感知到按键信号的时候才会变成1,come_on的初值也是0,只有感知到开始抢答信号的时候才会变为1,这个设计,既保证了只有按下开始抢答键之后才会开始倒计时(不受超前抢答信号的干扰),同时也保证了,正规抢答信号到来时停止计时的固有要求
(6) 同时因为我们设置的是20秒倒计时,基于此我设置的是两个4位的输出分别是time_outA,time_outB,如何寄存器变量count_down的信息转化成为模块的输出,想到用数据流语句:
在这里插入图片描述
一个要整数部分,一个要余数部分,巧妙地实现转变,堪称完美
(7) 我们还需要一个输出用于显示抢到题的小组,使用3位输出who,可以转接入数码管用于显示
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第6张图片
也是基本上有6个同样的模块
(8) 关于超前抢答信号,我们需要报警,这个时序逻辑其实是比较复杂的,但是因为有之前我们的一些铺垫,简单了不少;
(a)首先寄存器变量come_on随开始信号而被赋值,我们就是用come_on来感知start信号
在这里插入图片描述
(b)之前我们也提到了time_length是随抢答信号,而伴生的以为寄存器变量,我们用这个寄存器变量来感知抢答信号,初值为0,当抢答信号来的时候变为1,
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第7张图片
类似这样的模块同样有六个
©超前抢答信号怎么检验,其激励机制是怎样的,作用时间又是怎么确定的,这个问题十分复杂,时间有限,我只想到了让超前抢答警告蜂鸣器warn_buzzer与start的作用联系起来,因为start未作用的时候其初值为0,作用的时候初值为1,因而我们这一部分只用感知start的上升沿就好
在这里插入图片描述
同时,感知了start的上升沿就知道了两方对比的其中一方,而另一方就是抢答信号,
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第8张图片
关于抢答信号,一旦某队最先抢到,相应的time_length就会变为1,换句话说我们只需要判断start的上升沿来的时候寄存器time_length是否为1即可!
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第9张图片
(9) 如果是在正规抢答时间抢到了题目,如何来进行判断,这部分比上一部分更加复杂,使用time_length的上升沿来判断,然而还不足以,要体现是正规抢答时间,就必须要引用寄存器come_on,因为开始抢答信号到来的直接影响就是come-on变为1,当time_length的下降沿到来的时候,结合come_on为1,就可以确定,是正规抢答信号
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第10张图片
(10) 问题又来了,提示蜂鸣器的提示音时间怎么确定,这部分是最难的,我用time_length的上升沿来使提示蜂鸣器开始响,那么我们能不能用time_length来使提示蜂鸣器关闭呢,想到这里果断想到利用time_length的下降沿来使remind_buzzer重新回到低电平,这点很容易实现
就要想time_length的来历,是因为某个位置的抢答信号,我们就必须要定位是哪一个人抢到了题,在那个地方引发了time_length的上升沿,引入寄存器变量which_one来定位,定位成功之后使用switch语句来让time_length跳转回到低电平
在这里插入图片描述
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第11张图片
(11) 到此处为止,就可以确定抢到模块怎么写了(以下模块有六个)
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第12张图片
注意:这一部分并不需要感知start信号,也就是说抢答是永远在进行着的,不管开始没有开始,仅凭这个模块根本看不出来是超前抢答还是正规抢答!

四、实验数据及分析

对于实验仿真部分,因为我只有一个模块,就只用建立这一个模块的仿真即可。
(1) 关于时钟,设计的是50ns一个翻转,也就是一个20MHZ的时钟
在这里插入图片描述
(2) 关于仿真的初值设置
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第13张图片
(3) 情况(1)系统复位之后,在没有开始抢答的时候,若干人已开始抢答

基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第14张图片
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第15张图片
可以看到:
(a) 在start信号没有来的时候,倒计时停留在19,还没有开始倒计时
(b) 在200ns的时候复位,400ns左右的时候,start信号还没有来的时候,rusher1已经超前抢答,当时钟的上升沿到来的时候,三位输出端ho显示了1,说明是1号第一个答的,之后陆续每隔100ns都有一个rusher抢答,但是这个时候3位输出端who不变,说明其他抢答者的抢答通道被封锁了
(c) 接下来start信号到来了,这个时候就要判断在start信号上升沿到来之前有没有人超前抢答,显然是有的,那么报警蜂鸣器就会响

基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第16张图片
(d) 而start的下降沿一到来,报警蜂鸣器就不再响了
(4) 系统复位之后,开始信号到来,所有抢答者正规抢答
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第17张图片
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第18张图片
(a) 可以看到,当start 信号到来之后倒计时计数器开始计数,time_outA刚开始始终为1,等过10个时钟信号之后,变为0,time_outB二分频计数从0到9
(b) 在3300ns的时候rusher1的抢答信号到来,提示蜂鸣器响起,倒计时器停止倒计时,保留剩余时间显示。
© 从这个图中,我们可以看到,与我们的设计是一样的,如果抢答者rusher1不让抢答键复位的话,提示蜂鸣器会一直响起(这个有好处有坏处)
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第19张图片
(d) 同样不出我们所料,之后的抢答通道会被封锁,抢答信号被自动屏蔽掉。
(5) 如果是既有提前抢答的人,又有正规抢答的人
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第20张图片
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第21张图片
(a) 当复位信号到来之后,开始信号到来之前,rusher1超前抢答,开始信号到来之后,又有若干抢答者做作答。
(b) 我们可以看到,有人超前抢答,当开始信号到来的时候,系统会马上断定有人提前抢答,其他抢答通道会被封锁,倒计时计数根本不变,警告蜂鸣器会响起,提醒蜂鸣器不会响。
(6) 如果抢答者的抢答信号持续时间很长,在此持续时间段之内,start信号到来,看看会有什么影响:
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第22张图片
基于FPGA的六路抢答器(LED模块 蜂鸣器模块 计数器模块 键盘)_第23张图片
我们可以看到,警告报警器会发出警告,警示牌上会显示违规抢答的小组,不会出现这个最可怕的BUG

五、结论
在本实验之中,
(1) 我初步充分掌握了ISE14.7的基本功能实现操作方法,熟悉了这个软件的基本操作;
(2) 通过本实验,我对数电的知识有了更加深入的认识,学会了使用FPGA加上数电知识的综合利用,对于边沿使能的认知进一步加深了。
(3) 在本实验之中,我首先选择在CSDN,GITHUB等众多论坛上学习FPGA,一些模块化的实例再参考别人的基础上集众家之长编写自己的模块
(4) 项目完成度很高,项目成功实现了大部分功能,而且从一定程度上来说,实现的很巧妙
(5) 项目的求索精神,刚开始的时候依旧遵循开题时的大致思想,但做到项目中期的时候,战略放弃了之前所做的,不知道是对还是不对,做自己认为正确的事
(6) 独立思考与求助的结合,这里面这个度的把握,要经过自己的充分思考,充分思考之后,实在解答不出来的话再求助他人,形成一个很好的问题解决流程
(7) 学习新知的过程,对待新的知识,不能从太底层入手,会陷入一个温水煮青蛙的被动,应该双管齐下,融会贯通,(对待以C语言开发出来的语言这样做),基于工程实际,上手更快
(8) 工程实际过程之中会遇到各种实际问题,每个人都有不同的选择,每个选择的前路都是未知的,一定要有探索精神,不知道如果最后转变之后的程序编不出来,我会不会仍然坚持严格自己编程序,不看别人的;
(9) 看别人的代码再来编自己的从某种程度上来讲很容易,而且很显然会不经意间受他人的影响,不知道自己的真正能力;
(10) 持就是胜利!

注意:
总结:
(1)可以看到在程序之中我用的是宏定义延时时间为100ns,时钟是每隔50ns翻一翻,我们用的时钟是20MHZ;
(2)rset是复位键,start是主持人开始键,
(3)rusher相关键是选手按键(更像是开关);
(4)who是一个输出端,用于在显示屏上显示,由于有6名参赛者,我就设置了3位;
(5)time_outA和time_outB分别是四位输出端口;
(6)warn_buzzer是抢答警告蜂鸣器端口;根据start的上升沿有效
(7)remind_buzzer是抢答成功蜂鸣器端口;
(8)count_down是一个4位寄存器变量,我们用这个通过一定的操作转化成为time_outA和time_outB;
(9)3位寄存器变量which_one和who相似,都是用来记录抢答者;
(10)flag是抢中了的标志;flag说明你抢到了
(11)count_down和flag和which_one和time_length都是因为我们没有办法直接读取端口的值而设置的辅助寄存器变量

程序代码和仿真测试代码我将在下一篇文章公布!!!

你可能感兴趣的:(Verilog,HDL,数字设计与综合)