ZYNQ microphase 7020 开发板学习(2.键控灯)

ZYNQ microphase 7020 开发板学习(2.键控灯)按键消抖

代码基于microphase学习改进:

module key_led(
    input wire clk,
    input wire rst_n,
    input wire [2:0] key,
    output wire [2:0] led
    );
    reg [5:0] key_dd;
    always @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            key_dd <='d0;
        end
        else begin
            key_dd <= {key_dd[2:0],key};
        end
    end
    assign led = key_dd[5:3];
endmodule

机械按键本身在处理机械按键输入时。机械按键在被按下或松开时,通常不会立即达到稳定状态,而是会有一个短暂的抖动期。这些抖动会导致在按键的状态变化过程中产生多次高低电平的切换,从而造成误判。以上是微相提供的学习资料。
对于该示例,由于使用按键操作控制LED灯的亮灭,对于高频时钟,LED的亮灭体现对人眼而言识别并不需要消除这种抖动。想简单的实现键控灯只用将按键接入LED灯即可,所谓的按键抖动最终在LED亮灭上的体现在人眼上是分辨不出来的。因此以下代码也可满足实验需求:

module key_led(
    input wire clk,
    input wire rst_n,
    input wire [2:0] key,
    output reg [2:0] led
    );
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        // reset
        led <= 3'b000;
    end
    else begin
        led <= key;
    end
end
endmodule

对于机械按键的消除抖动的方式主要了解了以下3种,和大家分享:
1.基于寄存器的消除抖动

通过将按键信号保存到一个寄存器阵列中,并在时钟上升沿或复位信号下降沿进行更新。这样可以在一定程度上过滤掉抖动信号,但是否足够有效取决于具体的应用场景和抖动的时长。(微相提供的学习资料就是基于这一方式实现的,使用一个时钟周期的寄存器来延迟,将时钟信号取值保存之后一个周期判断)。

2.延时滤波法
考虑按键输入信号的长度在判断满足一定时长后,判定该按键有效。

module key_flag(
    input wire clk,
    input wire rst,
    input wire key,
    output reg key_flag
    );
    
parameter cnt_max = 5;
reg [2:0] cnt;
reg key_sync;

// 同步按键信号以避免亚稳态
always @(posedge clk or negedge rst) begin
    if (~rst) begin
        key_sync <= 1'b1;
    end else begin
        key_sync <= key;
    end
end

always @(posedge clk or negedge rst) begin
    if (~rst) begin
        // reset
        cnt <= 3'd0;
    end
    else if (~key_sync) begin
        if (cnt == cnt_max) begin
            cnt <= 3'd0;
        end
        else begin
            cnt <= cnt + 1'b1;
        end
    end else begin
        cnt <= 3'd0; // 如果按键未按下,计数器重置
    end
end

always @(posedge clk or negedge rst) begin
    if (~rst) begin
        key_flag <= 1'b1;
    end else begin
        key_flag <= (cnt == cnt_max) ? 1'b0 : 1'b1;
    end
end

endmodule

在自己写代码的过程中,出现了LED特别淡的情况,发现写的按键模块输出FLAG信号标志有效只占按键时长的1/5。仿真图像
而且按键抖动不止发生在按键触发,按键移除同样存在,于是想到和现状异或然后计时,不仅可以满足按键标志位和按键时长基本一致,而且可以满足按键移除和按键触发同时存在。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/08 18:46:11
// Design Name: 
// Module Name: key_led
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
例化每一位按键和标志位///
module key_led(
    input wire clk,
    input wire rst_n,
    input wire [2:0] key,
    output wire [2:0] led
    );

genvar i;
generate
    for(i=0;i< 3;i=i+1)begin:key_flag_gen
    key_flag key_top(
        .clk(clk),
        .rst(rst_n),
        .key(key[i]),
        .key_flag(led[i])
        );
    end 
endgenerate
endmodule
//-------------------------------------按键消除抖动模块------------------------------------
module key_flag(
    input wire clk,
    input wire rst,//低电平有效
    input wire key,
    output reg key_flag
    );
 
parameter cnt_max = 5;
reg [2:0] cnt;
reg key_sync;

// 同步按键信号以避免亚稳态
always @(posedge clk or negedge rst) begin
    if (~rst) begin
        key_sync <= 1'b1;
    end else begin
        key_sync <= key;
    end
end

always @(posedge clk or negedge rst) begin
    if (~rst) begin
        // reset
        cnt <= 3'd5;
    end
    else if (key_sync != key_flag) begin
        if (cnt == cnt_max) begin
            cnt <= 3'd0;
        end
        else begin
            cnt <= cnt + 1'b1;
        end
    end else begin
        cnt <= 3'd0; // 如果按键未按下,计数器重置
    end
end

always @(posedge clk or negedge rst) begin
    if (~rst) begin
        key_flag <= 1'b0;
    end 
    else if(cnt == cnt_max)begin
        key_flag <= key_sync ;
    end
    else begin
        key_flag <= key_flag;
    end
end

endmodule

在这里插入图片描述
可以看出,在和之前状态不同连续发生5次后,按键标识发生改变。实线按键消抖。

3.多采样法
考虑在一定的时间长度内,判断该按键信号的电平始终有效。使用将按键信号移位保存在多位的寄存器中,当多位寄存器的数值一样时,将该信号给到按键标识位。(个人感觉这个最简单)

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/08 20:14:11
// Design Name: 
// Module Name: key_led
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module key_led(
    input wire clk,
    input wire rst_n,
    input wire [2:0] key,
    output wire [2:0] led
    );

genvar i;
generate
    for(i=0;i< 3;i=i+1)begin:key_flag_gen
    key_flag key_top(
        .clk(clk),
        .rst_n(rst_n),
        .key(key[i]),
        .key_flag(led[i])
        );
    end 
endgenerate
endmodule
//-------------------这个简单又好理解------------------------
module key_flag(
    input wire clk,
    input wire rst_n, // 低电平有效
    input wire key,
    output reg key_flag
    );

    reg [4:0] key_sync;

// 同步按键信号以避免亚稳态同时寄存按键每次的采样值
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        key_sync <= 5'b0;
    end else begin
        key_sync <= {key_sync[3:0], key};
    end
end

// 判定每次的采样的数值均相同
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        key_flag <= 1'b0;
    end else if ((|key_sync == 0) || (&key_sync == 1)) begin
        key_flag <= |key_sync;
    end
end

endmodule

综合后的电路图也是最简单的满足了按键消抖的功能
在这里插入图片描述
第三种多采样法确实电路简单,容易理解,代码短。无敌

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值