FPGA拾忆_(10):按键控制蜂鸣器_边沿检测_按键消抖

这篇具有很好参考价值的文章主要介绍了FPGA拾忆_(10):按键控制蜂鸣器_边沿检测_按键消抖。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.硬件特征:

轻触式(回弹式)按键

        略

蜂鸣器:

分为蜂鸣器按照结构原理不同可分为压电式蜂鸣器和电磁式蜂鸣器。 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、 阻抗匹配器及共鸣箱、外壳等组成; 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。

其他资料:1
 

按键式蜂鸣器 verilog,fpga开发

发声原理:压电式蜂鸣器是利用压电效应原理工作的,当对其施加交变电压时它会产生机械振动发声; 电磁式蜂鸣器是接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场, 振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
压电式蜂鸣器和电磁式蜂鸣器由于发音原理不同, 产生的声音信号也不一样。 压电式结构简单耐用但音调单一,适用于报警器等设备; 而电磁式由于音质好,所以多用于语音、音乐等设备。 本次实验使用的蜂鸣器为电磁式蜂鸣器。
蜂鸣器按照驱动方式不同又可分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声

2.原理图:按键式蜂鸣器 verilog,fpga开发
3.端口以及模块结构:

按键式蜂鸣器 verilog,fpga开发

其中,key_debounce是将输入的key信号消抖后输出,这个模块的输出信号是key_filter,key_beep则是简单的控制逻辑,检测到有下降沿则判断为一次按键按下,beep信号翻转,最后是顶层模块将两个模块例化到一块,顶层模块中连接的信号key_filter为wire型,这样的结构清晰且富有条例,而我自己写的模块的结构应该如下面这个一样的 

按键式蜂鸣器 verilog,fpga开发关键模块:

消抖处理模块:电平跳变就进行计数,计数时间超过20ms说明此信号已经平稳,抖动信号已经过滤掉,将key信号直接赋值给key_filter即可。(我写的较为麻烦)

边沿检测模块:key信号是异步信号,所以要有个同步打拍子过程,然后进行边沿检测,

buf_res != buffer2 ,就说明有边沿出现。

4.代码技巧: 

人家的代码和我的代码对比:

module top_key_beep(
    input        sys_clk   ,    //系统时钟
    input        sys_rst_n ,    //系统复位,低电平有效

    input        key       ,    //按键    
    output       beep           //蜂鸣器
);

//parameter define
parameter  CNT_MAX = 20'd100_0000;   //消抖时间20ms

//wire define
wire key_filter ;                    //按键消抖后的值

//*****************************************************
//**                    main code
//*****************************************************

//例化按键消抖模块
key_debounce #(
    .CNT_MAX    (CNT_MAX)  
)u_key_debounce(
    .sys_clk       (sys_clk),
    .sys_rst_n     (sys_rst_n),
    .key           (key),
    .key_filter    (key_filter)
    );

//例化按键控制蜂鸣器模块
key_beep  u_key_beep(
    .sys_clk       (sys_clk),
    .sys_rst_n     (sys_rst_n),
    .key_filter    (key_filter),
    .beep          (beep)
    );

endmodule

/

按键消抖模块


module key_debounce(
    input        sys_clk   ,
    input        sys_rst_n ,

    input        key       ,   //外部输入的按键值
    output  reg  key_filter    //按键消抖后的值
);

//parameter define
parameter  CNT_MAX = 20'd100_0000;    //消抖时间20ms

//reg define
reg [19:0] cnt ;
reg        key_d0;            //将按键信号延迟一个时钟周期
reg        key_d1;            //将按键信号延迟两个时钟周期

//*****************************************************
//**                    main code
//*****************************************************

//对按键端口的数据延迟两个时钟周期
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        key_d0 <= 1'b1;
        key_d1 <= 1'b1;
    end
    else begin
        key_d0 <= key;
        key_d1 <= key_d0;
    end 
end

//按键值消抖
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) 
        cnt <= 20'd0;
    else begin
        if(key_d1 != key_d0)    //检测到按键状态发生变化
            cnt <= CNT_MAX;     //则将计数器置为20'd100_0000,
                                //即延时100_0000 * 20ns(1s/50MHz) = 20ms
        else begin              //如果当前按键值和前一个按键值一样,即按键没有发生变化
            if(cnt > 20'd0)     //则计数器递减到0
                cnt <= cnt - 1'b1;  
            else
                cnt <= 20'd0;
        end
    end
end

//将消抖后的最终的按键值送出去
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        key_filter <= 1'b1;
	//在计数器递减到1时送出按键值
    else if(cnt == 20'd1) 
		key_filter <= key_d1;
    else
		key_filter <= key_filter;
end

endmodule


按键控制逻辑

module key_beep(
    input        sys_clk,
    input        sys_rst_n,

    input        key_filter,   //消抖后按键值
    output  reg  beep          //蜂鸣器
    );

//reg define
reg    key_filter_d0;          //将消抖后的按键值延迟一个时钟周期

//wire define
wire   neg_key_filter;         //按键有效脉信号
 
//*****************************************************
//**                    main code
//*****************************************************

//捕获按键端口的下降沿,得到一个时钟周期的脉冲信号
assign  neg_key_filter = (~key_filter) & key_filter_d0;

//对按键端口的数据延迟一个时钟周期
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) 
        key_filter_d0 <= 1'b1;
    else 
        key_filter_d0 <= key_filter;
end

//每次按键按下时,就翻转蜂鸣器的状态
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        beep <= 1'b1;
    else if(neg_key_filter)  //有效的一次按键被按下
        beep <= ~beep;
    else
        beep <= beep;
end

endmodule

我的代码:

module key_beep(
    input           sys_clk,
    input           sys_rst_n,
    input           key,
    output  reg     beep
);
    wire key_filter;
    reg buffer2, beep_flag;
    //例化按键消抖模块
key_filter   
			key_filter_1(
                        .key(key),
                        .sys_clk(sys_clk),
                        .sys_rst_n(sys_rst_n),          
                        .key_filter(key_filter)
);
   
	
 //边沿检测电路
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            buffer2 <= 1'b0;
        else
            buffer2 <= key_filter;   
    end
    always@(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)
            beep_flag <= 1'b0;
        else if((key_filter == 1'b1)&&(buffer2 == 1'b0))
            beep_flag <= 1'b1;  //一个脉冲的按键标志信号
        else
            beep_flag <= 1'b0;
    end

    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)
            beep <= 1'b0;
        else if(beep_flag == 1'b1) //检测到一次按键
            beep <= ~beep;
        else
            beep <= beep; //保持
    end

endmodule



按键消抖

module key_filter (
    input           key,
    input           sys_clk,
    input           sys_rst_n,          
    output   reg    key_filter
);
    parameter CNT_MAX = 20'd1_000_000; //20ms
    reg [19:0] cnt;
    reg buffer1,buf_res;
    reg pose_flag,nege_flag;

    //ĺć­Ľććĺ­?
    always@(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)
            buffer1 <= 1'b0;
        else
            buffer1 <= key;
    end
    always@(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)
            buf_res <= 1'b0;
        else
            buf_res <= buffer1;
    end

    //ä¸čžšć˛żćŁćľçľčˇ?
    always@(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)begin
            pose_flag <= 1'b0;
            nege_flag <= 1'b0;
        end
        else if((buf_res == 1'b1)&&(buffer1 == 1'b0))begin
            pose_flag <= 1'b0;
            nege_flag <= 1'b1;
        end
        else if((buf_res == 1'b0)&&(buffer1 == 1'b1))begin
            pose_flag <= 1'b1;
            nege_flag <= 1'b0;
        end
        else
        begin
            pose_flag <= pose_flag;
            nege_flag <= nege_flag;
        end
    end



    //ćŁ?ćľĺ°čžšć˛żĺ°ąĺźĺ§čŽĄć?
    always@(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)
            cnt <= 10'd0;
        //ćŁ?ćľĺ°čžšć˛żďźĺźĺ§ć¸éśčŽĄć?
        else if(((buf_res == 1'b1)&&(buffer1 == 1'b0))||((buf_res == 1'b0)&&(buffer1 == 1'b1)))
            cnt <= 10'd0;
        //else if((pose_flag == 1'b1)||(nege_flag == 1'b1)) //ĺŞćć螚沿觌ĺďźĺ°ąĺźĺ§čŽĄć°ďźčŽĄć°čśčż20msďźćĺłçćŻä¸ćŹĄćé?
        else if(cnt == CNT_MAX - 1'b1)
            cnt <= 10'd0;
        else 
            cnt <= cnt + 1'd1;
    end
    //ĺ¤ć­čŽĄć°ćśé´ćŻĺŚč˝čžžĺ?20ms
    always@(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)
            key_filter <= 1'b0;
        else if((cnt == CNT_MAX - 1'b1)&&(nege_flag == 1'b1)) //莥ć°čžžĺ°1000ďźĺł20ms
            key_filter <= 1'b1; //ćä¸ćŹĄćéŽćä¸äş
        else if((cnt == CNT_MAX - 1'b1)&&(pose_flag == 1'b1))
            key_filter <= 1'b0;//ćéŽĺˇ˛çťćžĺźäş?
        else    
            key_filter <= key_filter;
    end


endmodule
5.仿真与验证:

按键式蜂鸣器 verilog,fpga开发

功能验证正确,但是我引入了较多的中间变量,而且输出的key_filter是与key信号消抖后的信号相反的,不过功能都验证正确了,也说明实现功能的方法可以有很多。

6.总结与易错点:

(1)几个重要且常用的模块:

        按键消抖模块,边沿检测模块,同步打拍子操作(解决亚稳态问题)

(2)加强对于自锁与非自锁概念的理解:

        自锁:一直输出有效电平。

        非自锁:仅输出一个周期的有效电平,需要自己对有效电平进行采集和保持。

(3)这次写testbench代码时遇到了一个从没遇到的问题:

        参数重定义,我的CNT_MAX是在key_filter模块定义的,然后key_beep例化了此模块,然后我在这个key_beep模块加入parameter语句or采用参数传递的模式(#(.CNT_MAX(CNT_MAX)))都不行,编译不报错,但是仿真的时候,也就是例化key_beep模块的时候,一直给我提示了CNT_MAX 不能被overwrite这个错误,但是正点原子的代码也参数重定义了,他的没有错误,我暂时还不知道问题出在哪,待定,等那天知道答案了来补充吧。贴一个将参数传递的文字:

verilog中参数传递与参数定义

待补充.....

(4)$stop(n)  和  $finish(n)的区别:可以参考一下

Verilog中$finish、$stop的使用与区别

over文章来源地址https://www.toymoban.com/news/detail-846265.html

到了这里,关于FPGA拾忆_(10):按键控制蜂鸣器_边沿检测_按键消抖的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32】STM32学习笔记-按键控制LED 光敏传感器控制蜂鸣器(08)

    led.h led.c key.h key.c main.c 电路图: 实物图: buzzer.h buzzere.c lightsensor.h lightsensor.cpp main.c 04-Key控制LED.rar 05-光敏传感器控制蜂鸣器.rar 参考: 【STM32】江科大STM32学习笔记汇总

    2024年04月23日
    浏览(54)
  • 【stm32】hal库学习笔记-GPIO按键控制LED和蜂鸣器(超详细!)

    注:本学习笔记基于stm32f4系列 使用的开发板为正点原子stmf407ZGT6探索者开发板 GPIO引脚使用时,可输入或输出数字信号 例如: 检测按键输入信号(Read_Pin)输出信号(Write_Pin) 输出信号点亮或熄灭LED GPIO引脚内部结构图 GPIO状态 输入浮空状态 :上拉下拉电阻均不使用(复位时

    2024年01月20日
    浏览(54)
  • 基于STM32CubeMX与keil采用按键外部中断方式控制LED与蜂鸣器

    这篇文章详细记录外部中断方式控制LED的亮灭以及蜂鸣器的开关;本文从原理图开始到最后实现功能,内容详细。 本栏目的所有都是基于STM32F407ZET6芯片,博主采用的是普中的天马F407开发板。 实现功能:LED0与LED1默认熄灭,蜂鸣器默认关闭。按下按键KEY0,控LED0亮灭;按下按

    2024年02月16日
    浏览(52)
  • 实验二 基于FPGA的分频器的设计(基本任务:设计一个分频器,输入信号50MHz,输出信号频率分别为1KHz、500Hz及1Hz。拓展任务1:用按键或开关控制蜂鸣器的响与不响。拓展任务2:用按键或开)

    1. 实验目的: (1) 掌握QuartusⅡ软件的层次型设计方法; (2) 掌握元件封装及调用方法; (3) 熟悉FPGA实验平台,掌握引脚锁定及下载。 2. 实验任务: (1) 基本任务:设计一个分频器,输入信号50MHz,输出信号频率分别为1KHz、500Hz及1Hz。 (2) 拓展任务1:用按键或开关

    2024年02月06日
    浏览(47)
  • PADS-按键、蜂鸣器、继电器PCB封装设计

    放置一个表贴端点,更改矩形尺寸,同时计算与原点的距离,这里我们按7.9+0.2最大值来放置   分步与重复,放置右边的端点,然后根据样式,先画一个矩形,然后改变宽的尺寸,3.8/1.2得出1.9 同样改一下长的坐标6.3/2=3.15  把线宽改细一点 W 0.1,或者双击改线宽  添加倒角

    2024年02月13日
    浏览(55)
  • fpga开发——蜂鸣器

    有源蜂鸣器和无源蜂鸣器          无源蜂鸣器利用电磁感应现象,为音圈接入交变电流后形成的电磁铁与永磁铁相吸或相斥而推动振膜发声,接入直流电只能持续推动振膜而无法产生声音,只能在接通或断开时产生声音。无源蜂鸣器的工作原理与扬声器相同。在使用方波

    2024年02月14日
    浏览(39)
  • 《FPGA学习》->蜂鸣器播放

    🍎 与其担心未来,不如现在好好努力。在这条路上,只有奋斗才能给你安全感。你若努力,全世界都会为你让路。 蜂鸣器的发声原理由振动装置和谐振装置组成,而蜂鸣器又分为无源他激型与有源自激型。本实验采用无源蜂鸣器,蜂鸣器的发声不同是靠频率不同进行控制的

    2024年02月08日
    浏览(45)
  • FPGA蜂鸣器播放音乐

      最近做EDA课设,看到自己的买的板子上有蜂鸣器,所以就打算做一个FPGA控制蜂鸣器播放音乐。   这里我使用的板子是睿智助学的FPGA开发板,板子上的芯片是 EP4CE6E22C8 ,如果是你使用的是其他开发板或者是自己做的板子,就根据原理图,在写完代码时绑定相应的引脚下

    2024年02月06日
    浏览(45)
  • 【FPGA】五、蜂鸣器播放音乐

    文章目录 前言 一、蜂鸣器简介 二、音频音符简介 三、任务要求 四、程序设计 1、设计思路  2、程序代码    总结         蜂鸣器(Buzzer)是现代常用的一种电子发声器,主要用于产生声音信号。它是一种一体化结构的电子讯响器,采用直流电压供电,被广泛用于计算机、

    2024年02月11日
    浏览(48)
  • 二、17【FPGA】无源蜂鸣器驱动实验

    学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。 学习视频:是根据野火FPGA视频教程——第二十讲 https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3      蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型。 压电式蜂鸣器是以压电陶瓷的压

    2023年04月25日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包