2_ZYBO FPGA 按键控制蜂鸣器 key_beep=>key_led

问题与思路

使用按键控制蜂鸣器发声。 初始状态为蜂鸣器鸣叫,按下开关后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫

按键抖动

image-20221202191430622

按键消抖

image-20221202191502184

系统框图

image-20221202191518440

消抖方式

  • 输入key的按键信号,输出一个value表示按键状态,以及一个flag表示状态是否稳定有效

  • 设置一个计数器,表示按键在同一状态稳定的时间,达到这个时间阈值表示按键按下有效

    • 这里的cnt设置为1_000_000个周期,每个周期20ns,也就是20_000_000ns=20ms=0.2s
  • 把key存在一个寄存器key_reg里,当key_reg != 按键key 表示状态发生了变化按键按下了,但是不知是抖动还是稳定,计数器赋初值

  • 否则key_reg=key表示按键没有变化处于稳定状态,计数器自减计算稳定时长,当时长达到阈值后即计数器为0后不再自减维持为0

image-20221202192638835

  • 如果以cnt为0作为判断条件,由于cnt在稳定后一直为0,那么key_flag和key_value会一直高电平和低电平,如果一直高电平蜂鸣器会认为一直处于按键变化状态,就会一直处于开关开关状态,所以我们只需要一个电平脉冲

  • 所以在计数器为1的时候拉高,为0的时候拉低,只一个周期为高电平

image-20221202194338977

key_debounce.v

注意这里是key_value = key 而不是 key_value = 1'b0

因为我们要的是按键按下持续0.02s后状态改变,而不是按键的任何状态即按下或松开持续0.02s就变

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

reg [19:0] cnt;
reg key_reg;

always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        key_reg <= 1'b1;
        cnt <= 1'b0;
    end
    else begin
        key_reg <= key;
        if(key_reg != key)
            cnt <= 20'd1_000_000;
        else begin
            if(cnt <= 1'b0)
                cnt <= 1'b0;
            else 
                cnt <= cnt - 1'b1;
        end
    end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        key_value <= 1'b1;
        key_flag <= 1'b0;
    end
    else begin
        if(cnt == 1)begin
            key_value <= key;
            key_flag <= 1'b1;
        end
        else begin
            key_value <= key_value;
            key_flag <= 1'b0;
        end
    end
end

endmodule

beep_control.v

module beep_control (
    input sys_clk,
    input sys_rst_n,
    input key,
    input key_value,
    input key_flag,
    output reg beep
);

always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        beep <= 1'b1;
    else if (key_flag && key_value == 1'b0)
        beep <= ~beep;
    else
        beep <= beep;
end
endmodule

top_key_beep.v

顶层模块连接两个底层模块,连接两个模块之间的变量需要定义位宽,类型为wire型,相当于水管连接两个模块,位宽是水管的粗细

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

wire key_value;
wire key_flag;

key_debounce u_key_debounce(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),

    .key(key),
    .key_value(key_value),
    .key_flag(key_flag)
);

beep_control u_beep_control(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),

    .key_value(key_value),
    .key_flag(key_flag),
    .beep(beep)
);


endmodule

tb_key_beep.v

需要模拟抖动

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/12/05 10:42:28
// Design Name: 
// Module Name: tb_key_beep
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_key_beep(

);
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;
    
    #60
    sys_rst_n = 1'b1;
    
    #40
    key = 1'b0;
    #100
    key = 1'b1;
    #40
    key = 1'b0;
    #120
    key = 1'b1;
    #40
    key = 1'b0;
    #140
    key = 1'b1;
    
    #40
    key = 1'b0;
    #240
    key = 1'b1;
    
    #40
    key = 1'b0;
    #280
    key = 1'b1;
end

always #10 sys_clk = ~sys_clk;

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

endmodule

仿真

cnt的阈值改为10,便于观察

image-20221205151621223

下载验证

注意的是zybo无复位按钮,这里将btn[1]作为sys_rst_n, btn[0]作为key,led[0]作为beep

将top函数的复位按钮前加上!取反,因为按钮是高电平有效的,所以key_control文件里的判断条件也要改为else if (key_flag && (key_value == 1'b1))

约束:

##Clock signal
set_property -dict { PACKAGE_PIN L16   IOSTANDARD LVCMOS33 } [get_ports { sys_clk }]; 

##Buttons
set_property -dict { PACKAGE_PIN R18   IOSTANDARD LVCMOS33 } [get_ports {key }]; #IO_L20N_T3_34 Sch=BTN0
set_property -dict { PACKAGE_PIN P16   IOSTANDARD LVCMOS33 } [get_ports { sys_rst_n }]; #IO_L24N_T3_34 Sch=BTN1



##LEDs
set_property -dict { PACKAGE_PIN M14   IOSTANDARD LVCMOS33 } [get_ports { beep }]; #IO_L23P_T3_35 Sch=LED0
posted @ 2022-12-05 16:25  xiongyuqing  阅读(109)  评论(0编辑  收藏  举报