洗子の小窝 但行己路 无问山海
歌曲封面 未知作品
  • 歌曲封面普通人生海洋Bo
  • 歌曲封面想想就烦Mikey-18
  • 歌曲封面卑微角色SevenJ李百万
  • 歌曲封面唉 (pt.5)河南说唱之神
  • 歌曲封面真心话就是大冒险河南说唱之神
  • 歌曲封面解决海底时光机
  • 歌曲封面Bloody Mary GirlShe Her Her Hers
  • 歌曲封面天天余佳运
  • 歌曲封面你(正式版)郑润泽
  • 歌曲封面小心温差Matt吕彦良
  • 歌曲封面于是郑润泽
  • 歌曲封面彻夜郑润泽

本网站由提供CDN加速服务

本网站由腾讯COS提供云存储服务

粤ICP备2022146502号-1

萌ICP备20240178号

Copyright © 2024 洗子の小窝

网站已运行 44 天 19 小时 24 分

Powered by Typecho & Sunny

2 online · 122 ms

Title

【FPGA】按键控制蜂鸣器

洗子

·

Article
本节的实验任务是使用开发板上的KEY0按键来控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下按键后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫。

一、项目总体思路的构建

首先我们要知道蜂鸣器是如何工作的?就拿我这个板子的蜂鸣器来说,BEEP处接入IO口,图中有个NPN型三极管, 基极Q1为低电平时截止,也就是低电平的发射极无法导通到集电极使蜂鸣器发声;当基极Q1为高电平时导通,此时发射极可以导通到GND形成回路,使蜂鸣器发声。

蜂鸣器电路设计图

通常我们所使用的开关为机械弹性开关,当我们按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的短时间内产生机械抖动,可能会产生短暂的电平波动,即按键抖动。

我们使用机械按键进行触发蜂鸣器工作,如果不进行按键消抖处理,可能会导致系统误触发或多次触发事件。因此,蜂鸣器的鸣叫控制需要考虑按键消抖算法,以确保只有在按键状态稳定时才产生鸣叫信号,避免误触发。这时候你可能会想之前的实验中我们也使用了机械按键来控制LED,为什么就不用按键消抖呢?是因为LED 的状态变化对于人眼来说相对较慢,不会像按键一样频繁地发生状态变化。

image-20240325185816114

按键消抖可分为硬件消抖和软件消抖。硬件消抖主要使用 RS触发器或电容等方法实现消抖,一般在按键较少时使用。软件消抖的原理主要为按键按下或松开后延时 5ms—20ms采样,也可以在检测到按键状态稳定后采样,即避开抖动区域后再采样。

image-20240325185835921

了解完这些必要的知识后,我们构建一个思维导图来确定我们的实验流程:

按键控制蜂鸣器顶层模块

我们根据上述的思路绘制图像来模拟按键控制蜂鸣器功能的实现,架构的设计图如下:

系统框图

波形图如下:

top_key_beep

二、编写代码

2.1 按键消抖模块

进入rtl文件夹,在此文件夹内建立key_debounce.v文件开始编写按键消抖模块程序。

为了实现按键消抖,我们知道抖动的时长为20ms左右,因此我们取时钟cnt最大值为1000000(1000000=20ms/20ns),我们通过对key进行打两拍,当key_d0和key_d1电平不同时,时钟cnt开始计时,且取最大值,当电平相同时,递减1直至为0。

♾️ verilog 代码:
module key_debounce(
    input        sys_clk, 
    input        sys_rst_n,
    input        key,
    output    reg    key_filter    //滤除消抖后的KEY
);

parameter CNT_MAX = 20'd1000000;

reg                    key_d0;
reg                    key_d1;
reg     [19:0]        cnt;

//对KEY打两拍
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

//如果按键有变化,重新计时20ms
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        cnt <= 20'd0;
    else if(key_d0 != key_d1) 
        cnt <= CNT_MAX;
    else if(cnt > 20'd0)
        cnt <= cnt - 20'd1;
    else
        cnt <= 20'd0;
end

//滤除抖动后的KEY赋值
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        key_filter <= 1'b1;
    else if(cnt == 20'd1)
        key_filter <= key_d1;
    else
        key_filter <= key_filter;
end
endmodule

2.2 按键控制蜂鸣器模块

进入rtl文件夹,在此文件夹内建立key_beep.v文件开始编写按键控制蜂鸣器模块程序。

我们对滤除消抖后的key打一拍与取反后的滤除消抖后的key相与检测出key_filter的下降沿,以此作为控制蜂鸣器的标志,当识别到下降沿时,蜂鸣器电平取反,即停止鸣叫。

♾️ verilog 代码:
module key_beep(
    input                sys_clk, 
    input                sys_rst_n,
    input                key_filter,    //滤除消抖后的KEY
    output        reg        beep
);

parameter CNT_MAX = 20'd1000000;

reg                    key_filter_d0;
wire                 neg_key_filter;    

assign neg_key_filter = key_filter_d0 & (~key_filter);

//对key_filter打一拍
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

2.3 例化整合模块

进入rtl文件夹,在此文件夹内建立top_key_beep.v文件开始编写例化整合模块程序。例化模块类似tb代码,将前面两个模块进行整合形成一个大模块。

♾️ verilog 代码:
module top_key_beep(
    input        sys_clk, 
    input        sys_rst_n,
    input        key,
    output        beep
);

parameter CNT_MAX = 20'd1000000;

wire key_filter;

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

使用vivado软件进行系统分析的得到例化后的系统框架如下:

例化后的系统框架

由此可以看出我们的RTL代码逻辑没有错误,接下来进行波形图仿真验证RTL代码是否正确。

三、验证仿真

在sim文件夹建立tb_top_key_beep.v文件,用来编辑仿真文件。这里注意自定的CNT_MAX例化代码,完整的tb代码如下:

♾️ verilog 代码:
`timescale 1ns/1ns  //仿真单位/仿真精度
module tb_top_key_beep();

parameter CLK_PERIOD = 20;
parameter CNT_MAX = 20'd10;

reg         sys_clk;
reg         sys_rst_n;
reg            key;
wire  beep;

initial begin
    sys_clk <= 1'b0;
    sys_rst_n <= 1'b0;
    key <= 1'b1;
    #200
    sys_rst_n <= 1'b1;
    #100
    key <= 1'b0;    //按键被按下
    #40
    key <= 1'b1;    //按键抖动
    #30
    key <= 1'b0;    //按键抖动结束
    #1000
    key <= 1'b1;    //按键松开
    #40
    key <= 1'b0;    //按键抖动
    #30
    key <= 1'b1;    //按键抖动结束    
end

always #(CLK_PERIOD/2) sys_clk =~ sys_clk;
    

top_key_beep #(
    .CNT_MAX        (CNT_MAX)
    )  

u_top_key_beep(
    .sys_clk        (sys_clk    ),
    .sys_rst_n      (sys_rst_n  ),
    .key            (key        ),
    .beep           (beep       )
    );
endmodule

仿真图像如下,由仿真图像我们可以看出与我们想要实现的目的相符合,起初蜂鸣器是鸣叫的,接受到滤除按键消抖的key后产生低电平停止鸣叫。

Clip_2024-03-31_18-20-37

四、上板验证

查询开发板资料,设置好IO口,并烧录,最终结果如下:

现在已有 0 条评论,2 人点赞
Comment
发表
搜 索 消 息 足 迹
你还不曾留言过..
你还不曾留下足迹..
博主