FPGA开发实验(2)- 按键(消抖)控制蜂鸣器实验

一、实验任务

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

二、程序设计

2.1 整体模块设计

本次实验需要 3 个输入的端口,分别为系统时钟、系统复位和按键输入,输出为蜂鸣器 beep 端口,模块框图如下图所示:
在这里插入图片描述

2.2 按键消抖模块设计

按键消抖模块我们的输入信号主要有系统时钟信号、系统复位信号与按键输入,输出为按键消抖后的值。模块框图如下图所示:
在这里插入图片描述
**绘制波形图:**我们消抖的过程就是滤除按键值保持时间小于 20ms 的值,那么我们需要做的就是在按键被按下或者被释放导致按键值产生变化时,从 20ms 开始倒计时,如果 20ms 的倒计时还没有完成按键值就再次产生变化,此时需要从头开始 20ms 倒计时,前一次导致按键值变化的操作视为无效操作,将该次变化视为按键抖动消除,否者保留。(50MHZ时钟,20ms需要50000000*0.02=1000000个时钟周期,)。
判断按键值变化,我们可以给按键值打两拍(一般外部输入信号我们都使用打拍处理消除亚稳态),然后比较按键两次的打拍值,第一次打拍值与第二次打拍值一致说明按键值没有变化,第一次打拍值与第二次打拍值不一致说明按键值产生了变化。
在这里插入图片描述
RTL代码key_debounce.v如下:

module key_debounce(
    input sys_clk,
    input sys_rst_n,
    input key,
    output reg key_filter
);

parameter CNT_MAX = 20'd100_0000;

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

//打两拍处理/
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        key_d0 <= 1'd1;
        key_d1 <= 1'd1;
    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 if(key_d0 != key_d1)
        cnt <= 20'd0;
    else if(cnt == CNT_MAX - 20'd1)
        key_filter <= key_d0;
    else if(cnt >=  CNT_MAX - 20'd1)
        cnt <= CNT_MAX - 20'd1;
    else
        cnt <= cnt + 20'd1;
end

endmodule

2.3按键控制蜂鸣器模块设计

按键控制蜂鸣器模块我们的输入信号主要有系统时钟信号、系统复位信号与消抖后的按键输入,输出
为蜂鸣器的值。模块框图如图所示:
在这里插入图片描述
绘制波形图: 本节实验任务是按下按键蜂鸣器响起,再次按下按键后蜂鸣器关闭。所以,我们可以通过打一拍实现。波形图如下:
在这里插入图片描述
RTL代码key_beep.v如下:

module key_beep(
    input sys_clk,
    input sys_rst_n,
    input key_filter,
    output reg beep
    );
    
reg key_filter_d0;
wire neg_key_filter;

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
    

2.4 顶层模块

module top_key_beep(
    input sys_clk,
    input sys_rst_n,
    input key,
    output beep
);

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

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

2.5 仿真验证

仿真代码tb_flow_led.v如下:

`timescale 1ns/1ns
module tb_top_key_beep();

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

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


initial begin
    sys_rst_n <= 1'b0;
    sys_clk <= 1'b0;
    key = 1'b1;
    #200 sys_rst_n <= 1'b1;
    #100 key <= 1'b0;
    #20 key <= 1'b1;
    #20 key <= 1'b0;
    #600 key <=  1'b1;
    #50 key <= 1'b0;
    #800 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

仿真结果如下图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值