首页 > 其他分享 >基于状态机的按键消抖模块

基于状态机的按键消抖模块

时间:2023-01-15 00:22:06浏览次数:66  
标签:key 消抖 999 状态机 按下 Key 按键 reg

本次案例是按着小梅哥的思路来写的,部分截图和文字来自其教学视频。

1、状态机的设定

image
 
image
 

2、模块代码

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:Lclone
// 
// Create Date: 2023/01/14 20:44:54
// Design Name: 
// Module Name: key_filter
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module key_filter(
    input           Clk,        //时钟信号
    input           Rst_n,      //复位信号
    input           Key_in,     //按键输入信号
    output  reg     Key_press,  //按键按下信号
    output  reg     Key_release //按键释放信号
    );
    
    reg [1:0]   key_reg;
    always @(posedge Clk or negedge Rst_n) begin
        if(Rst_n == 0)
            key_reg <= 0;
        else
            key_reg <= {key_reg[0],Key_in};//打拍子,为了捕获上升沿和下降沿
    end
    
    reg key_nedge;
    reg key_pedge;
    always @(posedge Clk or negedge Rst_n) begin
        if(Rst_n == 0)
            begin
                key_nedge <= 0;
                key_pedge <= 0;
            end
        else if(key_reg == 2'b10 )//下降沿捕获
            key_nedge <= 1'b1;
        else if(key_reg == 2'b01 )//上降沿捕获
            key_pedge <= 1'b1;
        else
            begin
                key_nedge <= 0;
                key_pedge <= 0;
            end
    end
    
    parameter  CNT_20MS = 1_000_000;
    reg [19:0]  cnt_20ms;
    reg [ 1:0]  state;
    always @(posedge Clk or negedge Rst_n) begin
        if(Rst_n == 0)
            begin
                state <= 0;
                cnt_20ms <= 0;
                Key_press <= 0;
                Key_release <= 0;
            end
        else case(state)
            0:
                begin
                    Key_release <= 0;
                    if(key_nedge == 1)
                        state <= 1;
                    else
                        state <= 0;
                end
            1:
                begin
                    if(cnt_20ms < CNT_20MS & key_pedge == 1)
                        begin
                            state <= 0;
                            cnt_20ms <= 0;
                        end
                    else if(cnt_20ms == CNT_20MS - 1)
                        begin
                            state <= 2;
                            cnt_20ms <= 0;
                            Key_press <= 1;
                        end
                    else
                        cnt_20ms <= cnt_20ms + 1'b1;
                end
            2:
                begin
                    Key_press <= 0;
                    if(key_pedge == 1)
                        state <= 3;
                    else
                        state <= 2;
                end
            3:
                begin
                    if(cnt_20ms < CNT_20MS & key_nedge == 1)
                        begin
                            state <= 2;
                            cnt_20ms <= 0;
                        end
                    else if(cnt_20ms == CNT_20MS - 1)
                        begin
                            state <= 0;
                            cnt_20ms <= 0;
                            Key_release <= 1;
                        end
                    else
                        cnt_20ms <= cnt_20ms + 1'b1;
                end
            default:;
        endcase
    end
endmodule

3、仿真

(1)$random函数的使用

rand = {$random(seed)} % 10_000_000;

  • 表示生成0-9_999_999范围内的随机数并赋值给rand;
  • 1个seed数对应着1个的随机数,可以通过设定seed的值来复现该随机数;
  • 可以去掉花括号后使生成的范围变成(-9_999_999) - 9_999_999;

(2)仿真代码

`timescale 1ns / 1ps

module key_filter_tb();

reg clk_50m;
initial clk_50m <= 1;
always #10 clk_50m <= ~clk_50m;

reg rst_n;
initial begin
    rst_n <= 0;
    #200
    rst_n <= 1;
end

reg         key_in;
wire        key_press;
wire        key_release;
key_filter  key_filter_inst(
    .Clk                (clk_50m),
    .Rst_n              (rst_n),
    .Key_in             (key_in),
    .Key_press          (key_press),
    .Key_release        (key_release)    
    );
    
initial begin
    key_in <= 1;
    #400
    press_key(1);
    #20
    press_key(2);
    #20
    press_key(3);
end

reg [31:0]rand;
task press_key;
    input [3:0]seed;
    begin
        key_in = 1;
        #20_000_000;
        repeat(5)begin
            rand = {$random(seed)} % 10_000_000;
            #rand key_in = ~key_in;
        end
        
        key_in = 0;
        #40_000_000;
        
        repeat(5)begin
            rand = {$random(seed)} % 10_000_000;
            #rand key_in = ~key_in;
        end
        key_in = 1;
        #40_000_000;
    end
endtask
endmodule

(3)仿真结果

第一次按下
image
 
 
第二次按下
image
 
 
第三次按下
image
 
 
实验结果:每次按下都能准确发出Key_press和Key_release信号,实验初步验证成功。

4、参考文献

[1]【零基础轻松学习FPGA】小梅哥Xilinx FPGA基础入门到项目应用培训教程】 https://www.bilibili.com/video/BV1va411c7Dz/?p=20&share_source=copy_web&vd_source=c6135c3b3a9878c08e2ddc91acdf6853&t=0

标签:key,消抖,999,状态机,按下,Key,按键,reg
From: https://www.cnblogs.com/Lclone/p/17052904.html

相关文章

  • Verilog实现基于状态机的序列检测
    一、状态机的基本概念硬件设计需要并行设计思想,而用Verilog描述的电路大多都是并行实现的,但是对于实际的项目工程,往往需要让硬件来做一些具有顺序的工作,这就要用到状态......
  • STM32掌机教程3,工程模板与带灯按键测试
    我们需要“脚手架”  关于代码,我想体现出这么一个过程:我是如何一步一步修改代码的。我认为,从学习的角度来考虑,直接看最终的代码没有什么意义。写代码就像工人盖房子,盖房......
  • [完全免费] 在线UML State Diagram 状态机图工具 - 教程第7部分
    状态机图用于对单个类对象,用例和整个系统的动态行为进行建模。换句话说,当一个状态机创建了对象的连接对象时,该对象成为状态机的所有者,例如,状态机所附加的对象可以是一个类,用......
  • 状态机模式
    有限状态机  FSM(FiniteStateMachine)状态机四要素现态、条件、动作、次态现态:是指当前所处的状态条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次......
  • Unity+Pico 手柄按键控制
    一、定义手柄按键API1、InputDevices.GetDeviceAtXRNode,通过XRNode获取对应的设备;2、XRNode是一个枚举类型,包含LeftEye、RightEye、CenterEye、Head、LeftHand、RightHa......
  • 牛客进阶题目20:根据状态转移写状态机-二段式
    把输出段与次态段合并即可`timescale1ns/1nsmodulefsm2( inputwireclk, inputwirerst, inputwiredata, outputregflag);//*************code****......
  • 牛客进阶题目19:根据状态转移写状态机-三段式
    普通三段式,根据状态转移图写即可。`timescale1ns/1nsmodulefsm1( inputwireclk, inputwirerst, inputwiredata, outputregflag);//*************c......
  • 碎冰挂船与按键精灵读内存地址
    昨天使用古老的按键精灵写个脚本,用来给老叶的海盗王挂船熟,每隔一个小时都要补一次船实在太麻烦了。好吧,古老的游戏,和古老的工具。一般很少上游戏了,也不想打装备,不想升级装......
  • C 语言实现简单有限状态机
    简介常说的状态机是有限状态机FSM,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。三个特征:状态总数(state)是有限的。任一时刻,只处在一种状态......
  • 有限自动状态机(Finite State Machine)
    有限状态自动机是拥有有限数量的状态,并且每个状态可以变换其他状态的数学模型。Afinite-statemachine(FSM)orfinite-stateautomaton(FSA,plural:automata),fin......