FPGA实战——按键控制蜂鸣器

目录

  • FPGA实战——按键控制蜂鸣器
    • 实验任务:
      • 蜂鸣器
    • 硬件设计
    • 程序设计
      • rtl文件
        • 按键消抖
      • ucf文件
        • 编译
        • RTL图
      • 补充——例化模块 的软件操作:
        • 下载及debug
    • 仿真

实验任务:

复位后蜂鸣器发声,按下按键后停止发声,再次按下继续发声。

蜂鸣器

有源无源的判断:
1.将蜂鸣器引脚朝上,可以看出有绿色电路板的一种是无源蜂鸣器,没有电路板而用黑胶封闭的一种是有源蜂鸣器。
2.万用表电阻档Rxl档: 用黑表笔接蜂鸣器 "+"引脚,红表笔在另一引脚上来回碰触,如果触发出咔、咔声的且电阻只有8Ω(或16Ω)的是无源蜂鸣器;如果能发出持续声音的,且电阻在几百欧以上的,是有源蜂鸣器。
本次实验使用有源蜂鸣器

硬件设计


当BUZZER引脚输出低电平时,PNP导通,蜂鸣器发声工作。

程序设计

rtl文件

这次我们用到了按键消抖,需要单独写一个模块比较方便,所以这节开始,我们就开始用多个.V文件,然后写顶层模块调用例化的底层模块这种写法了。回顾一下例化的知识(伪代码):

比如我已经定义了
<底层led模块>
module pled(input   sys_clk,output  led_value
);
那么我在顶层模块例化他的时候:
<底层模块>
首先定义顶层模块:
module top_flow_led(input sys_clk,output led
);
例化led模块时:
pled pled_u(.sysclk(sys_clk),.led_value(led)
);在例化模块中,.sysclk后的()表示的是输入,也就是说,因为在原来的pled模块中,sysclk是input,所以()中的变量为一个输入,现在,只需要将开发板上的晶振连接到顶层文件的input sysclk,然后这个顶层文件的sysclk再输入到led 的sysclk就实现了对底层模块的时钟的赋值。***********************而底层模块pled中 led_value是个output,所以这里.led_value(led)中led是作为led_value的输出接收信号,接收底层模块的输出,然后通过顶层模块,连接到开发板的LED灯上。***********************这就是通过例化连接到顶层模块的写法。具体后面的例子变量多,看起来可能更容易理解。

按键消抖

思想:当检测到按键值发生变化,也就是被按下时,将按键值保存,保存之后,每隔一段时间取按键值与原来值进行比较,如果持续20ms不变,就认为按键确实按下了。
(实际上,只需要检测到按键按下之后,启动计数器(不管怎么抖,都以变化后为计时起点重新计时),只要计数器在计数到20ms之前 ,按键值没有发生变化,就认为按键被按下)
那么我们写一个按键消抖模块,输入key(只用一个按键)输出一个key_flag表示按键被按下的标志,再输出一个key_value来存储key的值。
(一些疑问在最后的 下载与debug解决部分解决)

**************按键消抖模块**************
module key_debounce(           //消抖模块input       sys_clk,input       sys_rst_n,input       key,output reg  key_value,output reg  key_flag);reg      key_reg;           //存储key的值,相当于temp的作用
reg [19:0]  delay_cnt;         //计数器,计数20ms内key未变即按键被按下  20ms / 20ns = 100_0000,20位//按键延时计数器
always @ (posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginkey_reg   <= 1'b1;                  //1为未按下delay_cnt <= 20'd0;                     //计数器值清零endelse beginkey_reg <= key;                    //把key的值存储到寄存器中去if(key_reg != key)                     //说明按键值有变化!!!!!(不管怎么抖,都以变化后为计时起点重新计时)  delay_cnt <= 20'd100_0000;       //一旦检测到key值变化,就把计数器设到倒计时最大值。else if(key_reg == key)begin      //说明此时按键还是按下的状态if(delay_cnt > 20'd0)delay_cnt <= delay_cnt - 1'b1;else                         //else 它要等于自己!!!!!delay_cnt <= delay_cnt;endend
end//按键抖动判断
always @ (posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginkey_value  <= 1'b1;key_flag   <= 1'b0;endelse if(delay_cnt == 20'd1) begin         //从100_0000到了1,说明持续了20mskey_flag   <= 1'b1;key_value  <= key;                    //寄存此时的按键值endelse begin                                //计数器减到0key_flag   <= 1'b0;                      //这是个flag 标志位,不需要一直为1,只需要一个周期即可。key_value  <= key_value;end
end
endmodule

这里有一点需要讲解一下:

我们在key_reg <= key;之后,马上就判断key_reg和key是否相等,而且FPGA是并行的,这又是非阻塞赋值,那这不是肯定相等吗,其实不然。
always语句块是在posedge sys_clk的时候执行,其他时候不执行,而key_reg <= key; 这句虽然执行了,但是并不是马上把key的值给key_reg,而是需要等下一个clk上升沿才真正赋值,此时key_reg是上一clk的值,key就是实时的按键值,此时可以进行比较。

**************蜂鸣器模块**************
module beep_ctrl(input       sys_clk,input       sys_rst_n,input       key_value,input       key_flag,output reg  beep
);always @ (posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beep <= 1'b0;else if(key_flag && (~key_value))beep <= ~beep;
endendmodule
**************顶层模块**************
module top_key_beep(input       sys_clk,input       sys_rst_n,input       key,output      beep);//只需要作为导线把两个模块连接到一起即可,不需要是reg型
wire key_value;
wire key_flag;     key_debounce key_debounce_u(.sys_clk      (sys_clk)  ,.sys_rst_n    (sys_rst_n), .key          (key)      ,.key_value    (key_value),    .key_flag     (key_flag)    );beep_ctrl beep_ctrl_u(.sys_clk     (sys_clk)   ,.sys_rst_n   (sys_rst_n) ,.key_value   (key_value) ,.key_flag    (key_flag)  ,.beep        (beep)       ); endmodule


发现顶层模块并不是top_key_beep,所以我们设置一下,
如果设置完之后没有变化,说明我们的代码有错误,一定要好好检查。比如endmodule会忘记加。(如果代码添加进ise之后发现全编译的绿色按钮灰色,下方工具栏很多没有显示,也可能使endmodule未加)

这样就OK了。

ucf文件

NET sys_clk            TNM_NET = sys_clk_pin;
TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 20ns HIGH 50%;NET sys_clk     LOC = T8  | IOSTANDARD = LVCMOS33;
NET sys_rst_n   LOC = L3  | IOSTANDARD = LVCMOS33;##################   KEY    ############################
NET key         LOC = C3  | IOSTANDARD = LVCMOS33;##################   BEEP   ############################
NET beep        LOC = J11 | IOSTANDARD = LVCMOS33;

编译

编译报错:
Line 29: Target of concurrent assignment or output port connection should be a net type.
原因是:
例化时输出必须为wire类型的!!!!!

RTL图

上次我们用了第一种,是需要我们手动添加的,这次我们用第二个,就不需要手动添加了。

首先是这样的,但是我们还想看内部的图,那么我们可以双击这个rtl图,就可以看到内部

补充——例化模块 的软件操作:

首先两个底层模块加入进ISE,然后创建一个顶层模块。接下来,对于底层模块的例化,我们可以

将这段代码复制进顶层文件即可。

下载及debug

生成bit流文件,就可以下载进开发板了。
发现不能按一下就一直响,响了按一下不能停,问题出在下图那

我们先分析下逻辑,如果计数器从1百万减到1了,就可以把flag变成1,此时让key_value等于0,就是按下了。但是我们忽略了一点,就是按键松开的时候,也需要消抖!!!!那这时候,是不是消抖完还让他等于0呢,不是应该是等于稳定后的key值也就是把这里改成:key_value <=key;
如果按我们刚才那种,那没错,按下去是正常的,但是松开的时候,因为我们flag =1 ,但是按键值key_vlaue却还是0,此时,在下图的逻辑中相当于又按下了一次!!!!
另外,这个bug 也解决了了另外一个问题,就是为什么key_flag只持续了一个clk周期,不能一直等于1,这样对于后面的按键松开消抖不利,实验证明,这样按键会及其不灵敏!!

仿真

tb很简单,思想就是模拟按键抖动即可。

`timescale 1ns / 1nsmodule tb_top_key_beep;// Inputsreg sys_clk;reg sys_rst_n;reg key;// Outputswire beep;// Instantiate the Unit Under Test (UUT)top_key_beep u_top_key_beep (.sys_clk(sys_clk), .sys_rst_n(sys_rst_n), .key(key), .beep(beep));initial begin// Initialize Inputssys_clk   <= 1'b0;sys_rst_n <= 1'b0;key       <= 1'b1;// Wait 100 ns for global reset to finish#100;sys_rst_n <= 1'b1;// Add stimulus here#150         key  <= 1'b0;     // 在第250ns按下按键#1_000_000   key  <= 1'b1;      //模拟按键抖动1ms#1_000_000   key  <= 1'b0;#1_000_000   key  <= 1'b1;#1_000_000   key  <= 1'b0;#21_000_000  key  <= 1'b1;      //20ms之后松开按键#1_000_000   key  <= 1'b0;#1_000_000   key  <= 1'b1;#1_000_000   key  <= 1'b0;#1_000_000   key  <= 1'b1;#17_000_000  key  <= 1'b0;      //开始按下#1_000_000   key  <= 1'b1;#1_000_000   key  <= 1'b0;#1_000_000   key  <= 1'b1;#1_000_000   key  <= 1'b0;#17_000_000  key  <= 1'b1;      //松开#1_000_000   key  <= 1'b0;#1_000_000   key  <= 1'b1;#1_000_000   key  <= 1'b0;#1_000_000   key  <= 1'b1;#20_000_000  key  <= 1'b0;      //松开end//生成时钟  always #10 sys_clk = ~sys_clk;
endmodule

模拟了100ms之后的结果,我设置的是按键按下的延迟先20ms,后两个17ms,再一个20ms,可以看到符合我们的预期,之后前后两个才改变了beep的状态。

FPGA实战篇——【3】按键控制蜂鸣器相关推荐

  1. FPGA:基础入门按键控制蜂鸣器

    题目概述: 使用按键控制蜂鸣器发声.初始状态为蜂鸣器鸣叫,按下开关后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫. key_debounce.vmodule key_debounce( input s ...

  2. 51单片机怎么显示当前时间_(进阶篇)51单片机之按键控制蜂鸣器、数码管、按键值移位显示...

    一.实操演示- 按键控制蜂鸣器 1.图文详细 独立按键硬件电路 蜂鸣器硬件电路 2.连接方式: J20的第3号引脚连接到J7引脚,即P15连接J7. J29的第7.8号引脚连接到JP1的第1.2号引脚 ...

  3. 基于FPGA的两位按键控制LED数码管加减计数实验

    两位按键控制LED数码管加减计数实验 这是一篇拖了一个多月的文章,主要是基于FPGA利用按键消抖原理与动态数码管驱动原理相结合,来实现一个利用两位按键来控制数码管实现0-99的加法计数或者减法计数功能 ...

  4. FPGA——输入原理图实现按键控制发光二极管的亮灭

    文章目录 前言 一.FPGA的设计流程 二.按键控制发光二极管的亮灭的过程 (一)创建工程 (二)绘制原理图 (三)编译 (四)分配引脚 (五)仿真与时序分析 (六)配置FPGA (七)下载结果 总结 ...

  5. Arduino基础入门篇07—按键控制LED灯

    前面介绍了Arduino数字I/O,通过控制数字引脚输出来控制LED灯亮灭.本篇将介绍数字I/O的输入功能,通过检测按键状态来控制LED灯亮灭,把LED的亮灭变成人为可控制的. 1. 实验材料 Uno ...

  6. FPGA实战篇——【6】动态数码管

    FPGA实战--动态数码管 rtl文件 模块设计: 计数模块,产生数码管的数据 数码管显示驱动模块 时钟分频 数字转码(二进制->BCD码) 位选信号切换 调试warning: ucf文件 ** ...

  7. FPGA:基础入门按键控制LED灯

    题目概述: 使用按键控制LED灯亮灭. 无按键按下--LED全灭 按下KEYO--从右向左的流水灯效果 按下KEY1--从左向右的流水灯效果 按下KEY2--LED闪烁 按下KEY3--LED全亮 编 ...

  8. Arduino基础入门篇(按键控制LED)

    本篇我们主要介绍通过检测按键状态来控制LED灯亮灭,把LED的亮灭变成人为可控制的. 一.按键开关介绍 按键开关主要是指轻触式按键开关,也称之为轻触开关.按键开关是一种电子开关,属于电子元器件类,最早 ...

  9. c语言写按键控制蜂鸣器,51单片机用按键控制蜂鸣器发出do re mi fa...的声音,...

    满意答案 0fhk9 2017.12.30 采纳率:53%    等级:7 已帮助:1961人 T0HEQU 30H T0L EQU 31H ORG 0000H LJMP MAIN ORG 000BH ...

最新文章

  1. 宏基因组序列物种分类之kraken 1/2和Bracken的使用
  2. linux系统日志_第十二章:走进Linux世界——系统日志管理,日志轮转。
  3. 如何移植.NET Framework项目至.NET Core?
  4. java断点续传 http_http断点续传简单实现(java)
  5. kafka创建topic_Kafka实战宝典:一文带解决Kafka常见故障处理
  6. 喂。請罘葽缺蓆涐旳以后
  7. 分布式事务 - 梁飞的博客 - ITeye博客
  8. 【Flink】Flink 源码之OperatorChain
  9. 两边定宽,中间自适应布局的四种实现方法
  10. C语言 进制转换 将十进制转换为任意进制
  11. 一篇文章理清产品、运营、营销之间的概念和关系
  12. 小白刷LeeCode(算法篇)
  13. 【微前端】微前端——功能团队中缺失的一块拼图
  14. 亲测解决知网下载的正版国家标准打开不了
  15. 践行绿色发展理念,产业园区绿色转型发展之五大路径
  16. H3C服务器BIOS界面,全新改版图形化界面
  17. 哪吒之魔童降世视听语言影评_《哪吒之魔童降世》影评4篇
  18. Qos(Quality of Service)
  19. 【震惊】没有java环境也能运行jar,在不安装jdk下如何运行jar包
  20. 计算机系400分左右的学校,杭州2021年400分能上计算机学校吗

热门文章

  1. PCA降维工作原理及代码案例实现
  2. nordic 网站教程
  3. uml具有多种视图_UML的9种图及4+1视图简介(整理)
  4. 从菜鸟到大佬(四格漫画)
  5. 数组 Array (全世界最详细的数组解释)
  6. mysql创建视图,动态传入参数
  7. 如何把公众号里的文章页面,重写成html独立宣传页
  8. Kotlin实现的手机正则以及身份证正则判断
  9. oracle创建序列
  10. 爱立信四面楚歌断臂自救能否通过5G续写传奇?