全部版块 我的主页
论坛 经管考试 九区 经管在职研
1510 1
2025-12-05

1.1 概述

按键在实际操作过程中,由于其机械结构的特性,在按下或释放的瞬间会产生短暂而不稳定的抖动信号,这种现象被称为“按键抖动”。抖动时间通常持续5ms到10ms之间。若不加以处理,这类波动将影响系统的稳定运行,并降低输入响应的准确性。

为确保系统可靠识别按键动作,必须对抖动进行消除处理。常见的消抖方法包括使用RS触发器、电容滤波等硬件方式,以及通过程序实现的软件消抖方案。本章节采用FPGA内部逻辑实现软件消抖,利用时序控制跳过抖动阶段,从而准确判断按键的真实状态。

软件消抖的核心思想是:在检测到按键状态变化后,延时一段时间(如10ms),再次确认按键是否仍处于该状态,若一致则认为是一次有效的操作。这种方法简单高效,适用于大多数基于FPGA的设计场景。

1.3 key模块的设计

鉴于按键去抖功能具有较高的通用性,可将其封装为独立的功能模块,便于后续项目中的复用。以下为key模块的设计说明:

首先,对系统主时钟进行分频处理,生成周期为10ms的使能信号,用于驱动状态机的定时判断。整个消抖流程由四个状态构成:

  • KEY_S0:初始状态,持续监测按键是否被按下。一旦检测到按下信号,则进入下一状态。
  • KEY_S1:等待10ms后重新检测按键状态。若按键仍然处于按下状态,则确认为有效按下,转入KEY_S2;否则返回KEY_S0,视为误触或抖动。
  • KEY_S2:开始检测按键是否已释放。若检测到松开动作,则进入KEY_S3。
  • KEY_S3:再次延时10ms后验证按键是否确实已释放。若确认释放,则回到初始状态KEY_S0;否则保持在KEY_S2。

当状态从KEY_S1成功转移至KEY_S2时,表示完成一次完整的按键按下过程,此时输出一个脉冲高电平信号key_cap,作为外部电路的动作触发信号。

module key #
(
parameter CLK_FREQ = 100000000
)
(
input clk_i, input key_i, output key_cap
);

//10ms parameter CNT_10MS = (CLK_FREQ/100 - 1'b1);
parameter KEY_S0 = 2'd0;
parameter KEY_S1 = 2'd1;
parameter KEY_S2 = 2'd2;
parameter KEY_S3 = 2'd3; reg [24:0] cnt10ms = 25'd0;

(*mark_debug = "true"*) reg [1:0] key_s = 2'b0;
(*mark_debug = "true"*) reg [1:0] key_s_r = 2'b0;
(*mark_debug = "true"*) wire en_10ms ; 

assign en_10ms = (cnt10ms == CNT_10MS); 
assign key_cap = (key_s==KEY_S2)&&(key_s_r==KEY_S1); 

always @(posedge clk_i)begin
    if(cnt10ms < CNT_10MS) 
        cnt10ms <= cnt10ms + 1'b1; 
    else
        cnt10ms <= 25'd0; 
end

always @(posedge clk_i)begin
    key_s_r <= key_s; 
end

always @(posedge clk_i)begin
    if(en_10ms)begin
        case(key_s)
            KEY_S0:begin
                if(!key_i)
                    key_s <= KEY_S1; 
            end
            KEY_S1:begin
                   if(!key_i)
                        key_s <= KEY_S2; elsekey_s <= KEY_S0; 
            end
            KEY_S2:begin
                if(key_i)
                    key_s <= KEY_S3; 
            end
            KEY_S3:begin
                if(key_i)key_s <= KEY_S0; 
                else    key_s <= KEY_S2; 
            end
        endcase
    end
end
endmodule

1.4 key模块的调用与LED控制

在顶层设计中调用上述key模块,每当key_cap信号产生一次有效脉冲,即触发连接的LED状态翻转一次。具体表现为:每按一次按键,对应的LED灯点亮或熄灭交替变化。

实现代码如下所示:

module Key_Jitter(
    input clk_i, 
    input rst_n_i, 
    input key_i, 
    output [2:0] led_o
);
(*mark_debug = "true"*) reg [2:0] led_o;
(*mark_debug = "true"*) wire key_cap;

always @(posedge clk_i)begin
    if(!rst_n_i)begin
        led_o <= 4'b0000;
    end
    else if(key_cap)begin
        led_o <= ~led_o;
    end
end

key#(
    .CLK_FREQ(100000000)
)key0(
    .clk_i(clk_i),
    .key_i(key_i),
    .key_cap(key_cap)
);

endmodule

1.2 硬件资源配置

FPGA开发板上配备多个独立按键,均可与FPGA引脚直接连接。本实验选用SW1按键作为输入源,配合一个LED指示灯用于输出反馈。各按键工作原理相同,故以单一按键为例即可代表整体应用逻辑。

功能目标为:每次完整按下并释放SW1按键,LED状态发生一次切换——首次按下点亮,再次按下熄灭,依此类推。

仿真与验证流程

1、创建新的仿真测试文件,其源码如下所示:

`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 11:11:11 11/31/2025
// Design Name: zhou_bin_yyd
// Module Name:
// Project Name: Key_Jitter
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: Key_Jitter
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module Key_Jitter_TB;
// Inputs
reg clk_i;
reg rst_n_i;
reg key_i;
wire [3:0] led_o;

// Instantiate the Unit Under Test (UUT)
Key_Jitter uut (
    .clk_i(clk_i),
    .rst_n_i(rst_n_i),
    .key_i(key_i),
    .led_o(led_o)
);
initial
    begin
        // Initialize Inputs
        clk_i = 0;
        forever
        #5 clk_i=~clk_i;
    end

initial
    begin
        // Initialize Inputs
        rst_n_i = 0;
        #100;
        rst_n_i=1;
        key_i = 1;
        #10000;
        forever
        begin
            key_i = 0;
            // Wait 100 ns for global reset to finish
            #100;
            key_i=1; #1000;
            key_i=0; #1000;
            key_i=1; #2000;
            key_i=0; #5000;
            #50000000;
            key_i=1;
            key_i=0; #1000;
            key_i=1; #2000;
            key_i=0; #1000;
            key_i=1; #2000;
            #50000000;
            key_i=0;
        end
    end
endmodule

2、进入仿真环境:选择 SIMULATION → Run Simulation → Run Behavioral Simulation,启动行为级仿真。

3、执行仿真过程。

4、观察仿真波形结果,验证消抖逻辑是否正确执行。

5、完成代码编译,生成可编程固件。

6、下载固件至FPGA设备,进行实物测试。实验结果显示:每次按下SW1按键,LED均能准确地实现亮灭切换,无误触发或漏响应现象。

为进一步体现消抖机制的重要性,可尝试调整延时参数至极小或极大值。此时会发现,尽管按键已被按下,但LED可能无反应或出现多次翻转,这正是未有效避开抖动区间所导致的结果。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

全部回复
2025-12-27 17:47:39
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群