• 【【萌新的FPGA学习之按键控制蜂鸣器之消抖介绍】】


    萌新的FPGA学习之按键控制蜂鸣器之消抖介绍

    本板子携带了一个有源蜂鸣器
    有源蜂鸣器相对于无源蜂鸣器更加简单,只要加上合适的直流电压就可以发声
    实验目的 :
    本节实验任务是使用领航者上的 PL KEY0 按键来控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下按键后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫。
    对于按键消抖 : 软件消抖的原理是当按键按下或松开后,由处理器延时5ms至20ms,然后再对按键状态进行采样判断

    我们消抖的过程就是滤除按键值保持时间小于 20ms 的值,那么我们需要做的就是在按键被按下或者被释放
    导致按键值产生变化时,从 20ms 开始倒计时,如果 20ms 的倒计时还没有完成按键值就再次产生变化,此
    时需要从头开始 20ms 倒计时,前一次导致按键值变化的操作视为无效操作,将该次变化视为按键抖动消除;
    如果计完 20ms 按键状态一直没有改变,说明此次按键被按下或者被释放是有效操作,将此次按键第二次的
    打拍的值赋值给按键消抖后的信号 key_filter。

    我们来讲述一下 消抖模块的工作机理和代码

     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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们判断是否是真正的值用20ms作为一个阶段
    我们用非阻塞逻辑选取了两个节点 正好是一前一后的状态 只要我们在后续上判断两数不相等 那说明两种情况
    说明什么 说明要么是从0到1 要么是从1到0 我们不知道是不是毛刺从而产生跳变 所以我们就在这 此时此刻将数据设置位cnt 20ms 的值
    接下来 当两个数据相等我们就开始相减

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

    我们解析代码其中有一段 在代码相等时为什么要试探是否大于0 因为 如果不大于0 可能处于刚刚复位的阶段
    这也是为什么他计算正好要到1开始跳变的原因

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在倒计时到 1 时将此时按键 key_d1 的值赋值给按键消抖后的值 key_filter。
    按键消抖后的值 key_filter 为低电平表示按键被按下,按键消抖后的值 key_filter 为高电平则表示按键被释
    放。
    由本章硬件设计可知,我们给蜂鸣器 beep 高电平时蜂鸣器会发声鸣叫,我们给蜂鸣器低电平时蜂鸣器
    停止鸣叫,初始化时我们给蜂鸣器赋值高电平;并且在按键控制 LED 实验的硬件设计我们了解过,按键没
    有被按下时为高电平,按键被按下时为低电平,所以可以通过检测按键值的下降沿来判断按键是否被按下。
    如果检测到按键下降沿,表示按键被按下,此时我们取反一次 beep 值,beep 值由高电平变为低电平,蜂鸣
    器停止发声。等待下一次按键被按下,蜂鸣器的值再次取反,会由低电平变为高电平,蜂鸣器会再次发声,
    至此实现了使用按键控制蜂鸣器发声的任务。
    我们的做法就是边沿检测,当每次检查到被按下时,开始取反beep使得蜂鸣器的发声状态开始变化

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这一段非常有深度虽然我不懂但是可以用 因为他用的是判断下降沿 那我就截取一个信号令它和上一个信号交替
    然后assign x= (~0)& 1 ; 这样正好捕获下降沿

    自己编写的代码

    module keydebounce(
        input clk,
        input rst_n,
        input key,
        output reg  out
      );
    
      // define 20ms  first we use 1/50M = 20ns   20ms/20ns=100_0000
    
      parameter CNT_MAX = 20'd100_0000; //  idk  y  20'd
    
      reg[19:0] cnt;
      reg  key0;   // one cut
      reg  key1;   //  two cut
    
      always@(posedge clk or negedge rst_n )
      begin
        if(rst_n==0) begin
          
            key0 <= 1'b1;
            key1 <= 1'b1;
          
        end
          else
            key0    <=  key;
        key1    <=  key0;      //  we can use this  contribute  two state
      end
    
    
      //  next  we should  contribute  a  build  module
      always@(posedge clk or  negedge  rst_n)
      begin
        if( rst_n   == 0)
          
            cnt <=  0 ;
          
          else   begin
            if(key0   !=  key1)
           
              cnt <= CNT_MAX;
            
            else begin
                 if(cnt > 0)
            
                cnt <=  cnt - 1;
            
              else
                cnt <= 0 ;
              end
      end
    end
    
    
      // get  answer
       always@( posedge  clk or  negedge  rst_n) begin 
        if(rst_n    ==  0)
        
             out    <=  1 ;  
        
        else if(cnt ==  1)
            out <= key1;
            else
                out <=  out ;
            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
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    下面是 beep的代码

    module key_beep(
        input clk,
        input rst_n,
        input key_filter,
        output reg beep
      );
    
      //  we use  down  to  test
    
      //  first  we use one state
      reg     key0;
      wire    neg_key_filter;
    
    
      assign neg_key_filter = (~key_filter)&key0;
    
    
      //set  down
      always@(posedge clk or negedge rst_n)
      begin
        if(rst_n == 0)
          key0 <= 1'b1;
        else
          key0 <= key_filter  ;
      end
    
    
    
      always@(posedge clk or  negedge rst_n)
      begin
        if(rst_n    ==  0)
          beep <= 1;
        else if(neg_key_filter)
          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
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    平台化设计产品存在的问题
    如何用人工智能自动玩游戏
    基于随机森林实现特征选择降维及回归预测(Matlab代码实现)
    基础 | JVM - [Object & 锁升级]
    机试算法学习
    黄菊华老师,Java Servlet毕业设计毕设辅导课(4):Servlet 实例
    Android开发:(AndroidStudio模拟器)如何将模拟器语言设置为中文 && 模拟器输入法更改为中文输入 && 键盘输入中文
    OpenCV 配置 VS 2022并识别人脸框出
    琐碎的容易忽视的知识
    C++引用
  • 原文地址:https://blog.csdn.net/weixin_50965981/article/details/133267358