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


    2_ZYBO FPGA 按键控制蜂鸣器 key_beep=>key_led - xiongyuqing - 博客园 (cnblogs.com)

    问题与思路

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

    按键抖动

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    仿真

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    陈吉宁经典演讲:平庸与卓越的差别
    Vue组件化编程开发
    如何使一个不定宽和不定高的元素垂直水平居中
    Ubuntu22.04安装,SSH无法连接
    Windows如何删除“$WINDOWS.~BT“文件夹,解决权限不足无法删除
    Python 自动化脚本系列:第3集
    初识进程以及父子进程
    Elasticvue - 用于浏览器的免费开源 Elasticsearch GUI
    站在健康保障行业拐点,轻松集团如何“无界开元”?
    mulesoft What‘s the typeOf(payload) of Database Select
  • 原文地址:https://blog.csdn.net/qq_45364953/article/details/128188878