饥饿的半导体 2023-04-11 22:55 采纳率: 85.7%
浏览 67
已结题

FPGA多个按键消抖

FPGA用Verilog设计倒计时,按键控制时钟复位、启动/暂停、加1、减1
但是key3和key4不能够正常消抖,如何修改代码?

顶层文件

module counter
(
    clk , //时钟
    rst , //复位
    hold , //启动暂停按键
    seg_led_1 , //数码管 1
    seg_led_2 , //数码管 2
    led, //led
    key
    //buzz  //蜂鸣器
);
input clk,rst;
input hold;
input [4:3]key; //key1复位rst,key2暂停hold,key3加一,key4减一

output [8:0] seg_led_1,seg_led_2;
output reg [7:0] led;

//output reg buzz;

wire clk1h; //1Hz 时钟
wire hold_pulse; //暂停按键消抖后信号

wire key3_pulse;//key_pulse[3]加一按键消抖后信号
wire key4_pulse;//key_pulse[4]减一按键消抖后信号

reg key3_flag;//加一按键标志位
reg key4_flag;//减一按键标志位

reg hold_flag; //按键标志位
reg back_to_zero_flag ; //计时完成信号
reg [6:0] seg [9:0];
reg [3:0] cnt_ge; //个位
reg [3:0] cnt_shi; //十位

initial
begin
    seg[0] = 7'h3f; // 0
    seg[1] = 7'h06; // 1
    seg[2] = 7'h5b; // 2
    seg[3] = 7'h4f; // 3
    seg[4] = 7'h66; // 4
    seg[5] = 7'h6d; // 5
    seg[6] = 7'h7d; // 6
    seg[7] = 7'h07; // 7
    seg[8] = 7'h7f; // 8
    seg[9] = 7'h6f; // 9
end

// 用于分出一个 1Hz 的频率
divide #(.WIDTH(32),.N(12000000)) U1 (
    .clk(clk),
    .rst_n(rst),
    .clkout(clk1h)
);

// 启动/暂停按键进行消抖
debounce U2(
    .clk(clk),
    .rst(rst),
    .key(hold),
    .key_pulse(hold_pulse)
);


debounce3 U3 (
    .clk(clk),
    .rst(rst),
    .key(key[3]),
    .key_pulse(key3_pulse)
);

debounce4 U4 (
    .clk(clk),
    .rst(rst),
    .key(key[4]),
    .key_pulse(key4_pulse)
);


//按键动作标志信号产生
always @ (posedge hold_pulse)
    if(!rst==1)
    hold_flag <= 0;
else
    hold_flag <= ~hold_flag;
    
always @ (posedge key3_pulse)
    if(!rst==1)
    key3_flag <= 0;
else
    key3_flag <= ~key3_flag;
    
always @ (posedge key4_pulse)
    if(!rst==1)
    key4_flag <= 0;
else
    key4_flag <= ~key4_flag;
    

//计时完成标志信号产生
always @ (*)
    if(!rst == 1)
        back_to_zero_flag <= 0;
    else if(cnt_shi==0 && cnt_ge==0)
        back_to_zero_flag <= 1;
    else
        back_to_zero_flag <= 0;

//20 秒倒计时控制
always @ (posedge clk1h or negedge rst) begin
    if (!rst == 1) begin
    cnt_ge <= 4'd0;
    cnt_shi <= 4'd2;
    end
    
    else if(hold_flag == 1)begin    
    cnt_ge <= cnt_ge;
    cnt_shi <= cnt_shi;
        if(key3_flag == 1)begin   //在暂停界面下调整数值
        cnt_ge <= cnt_ge + 1;
            if(cnt_ge == 4'd9)begin
            cnt_ge <= 4'd0;
            cnt_shi <= cnt_shi + 1;
            end
        end
        if(key4_flag == 1)begin   
        cnt_ge <= cnt_ge - 1;
            if(cnt_ge == 4'd0)begin
            cnt_ge <= 4'd9;
            cnt_shi <= cnt_shi - 1;
            end
        end    
    end
    
    else if(cnt_shi==0 && cnt_ge==0) begin
    cnt_shi <= cnt_shi;
    cnt_ge <= cnt_ge;
    end
    else if(cnt_ge==0)begin
    cnt_ge <= 4'd9;
    cnt_shi <= cnt_shi-1;
    end
    else
    cnt_ge <= cnt_ge -1;
end

//计时完成点亮 led
always @ ( back_to_zero_flag)begin
    if (back_to_zero_flag==1)
    led = 8'b0;
    else
    led = 8'b11111111;
end

/*//计时完成蜂鸣器鸣叫
always @ ( back_to_zero_flag)begin
    if (back_to_zero_flag==1)
    buzz <= 1'b0;  //低电平触发
    else
    buzz <= 1'b1;
end*/


assign seg_led_1[8:0] = {2'b00,seg[cnt_ge]};
assign seg_led_2[8:0] = {2'b00,seg[cnt_shi]};

endmodule

消抖模块

module debounce (clk,rst,key,key_pulse);
parameter N = 3; //要消除的按键的数量
input clk;
input rst;
input [N-1:0] key; //输入的按键
output [N-1:0] key_pulse; //按键动作产生的脉冲
reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值
reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值
wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲

//利用非阻塞赋值特点, 将两个时钟触发时按键状态存储在两个寄存器变量中
always @(posedge clk or negedge rst)
begin
    if (!rst) begin
    key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1, {}中表示N个1
    key_rst_pre <= {N{1'b1}};
    end
    else begin
    key_rst <= key; //第一个时钟上升沿触发之    后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
    key_rst_pre <= key_rst; //非阻塞赋值。 相当于经过两个时钟触发, key_rst存储的是当前时刻key的值, key_rst_pre存储的是前一个时钟的key的值
    end
end

assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。 当key检测到下降沿时, key_edge产生一个时钟周期的高电平
reg [17:0] cnt; //产生延时所用的计数器, 系统时钟12MHz, 要延时20ms左右时间, 至少需要18位计数器

//产生20ms延时, 当检测到key_edge有效是计数器清零开始计数
always @(posedge clk or negedge rst)
begin
    if(!rst)
    cnt <= 18'h0;
    else if(key_edge)
    cnt <= 18'h0;
    else
    cnt <= cnt + 1'h1;
end

reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量
reg [N-1:0] key_sec;

//延时后检测key, 如果按键状态变低产生一个时钟的高脉冲。 如果按键状态是高的话说明按键无效
always @(posedge clk or negedge rst)
begin
    if (!rst)
    key_sec <= {N{1'b1}};
    else if (cnt==18'h3ffff)
    key_sec <= key;
end

always @(posedge clk or negedge rst)
begin
    if (!rst)
    key_sec_pre <= {N{1'b1}};
    else
    key_sec_pre <= key_sec;
    end
assign key_pulse = key_sec_pre & (~key_sec);

endmodule

  • 写回答

1条回答 默认 最新

  • 「已注销」 2023-04-11 23:22
    关注

    以下内容部分参考ChatGPT模型:


    针对按键消抖的问题,可以在按键模块中添加一个状态机,来实现按键的消抖。具体思路如下:

    1. 在按键模块中添加一个状态机,用来检测按键的状态。
    2. 当按键被按下时,状态机进入一个等待状态,等待一定的时间后再检测按键状态。
    3. 如果按键状态依然为按下状态,则认为按键已经稳定,可以进行处理,否则继续等待。
    4. 处理完按键后,状态机返回空闲状态,等待下一次按键操作。

    下面是一个简单的按键消抖的Verilog代码示例:

    module debounce (
        input clk,
        input button,
        output reg debounced_button
    );
    
    parameter debounce_time = 10; // 按键消抖时间,单位为时钟周期
    
    reg [3:0] state = 4'b0000; // 按键状态机的状态
    reg [3:0] counter = 4'b0000; // 按键消抖计数器
    
    always @ (posedge clk) begin
        case (state)
            4'b0000: // 空闲状态
                if (button == 1) begin
                    state <= 4'b0001;
                    counter <= 4'b0000;
                end else begin
                    debounced_button <= 0;
                end
            4'b0001: // 等待状态
                if (button == 0) begin
                    state <= 4'b0000;
                    debounced_button <= 1;
                end else if (counter < debounce_time) begin
                    counter <= counter + 1;
                end else begin
                    state <= 4'b0010;
                end
            4'b0010: // 按下状态
                if (button == 0) begin
                    state <= 4'b0011;
                    counter <= 4'b0000;
                end else begin
                    debounced_button <= 1;
                end
            4'b0011: // 等待松开状态
                if (button == 1) begin
                    state <= 4'b0010;
                    debounced_button <= 0;
                end else if (counter < debounce_time) begin
                    counter <= counter + 1;
                end else begin
                    state <= 4'b0000;
                end
            default:
                state <= 4'b0000;
                debounced_button <= 0;
        endcase
    end
    
    endmodule
    

    在顶层文件中,将debounce模块实例化,并使用debounced_button信号来代替原来的按键信号,即可实现按键消抖。


    如果我的建议对您有帮助、请点击采纳、祝您生活愉快

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 4月13日
  • 创建了问题 4月11日

悬赏问题

  • ¥15 Apache显示系统错误3该如何解决?
  • ¥30 uniapp小程序苹果手机加载gif图片不显示动效?
  • ¥20 js怎么实现跨域问题
  • ¥15 C++dll二次开发,C#调用
  • ¥15 请教,如何使用C#加载本地摄像头进行逐帧推流
  • ¥15 Python easyocr无法顺利执行,如何解决?
  • ¥15 为什么会突然npm err!啊
  • ¥15 java服务连接es读取列表数据,服务连接本地es获取数据时的速度很快,但是换成远端的es就会非常慢,这是为什么呢
  • ¥15 vxworks交叉编译gcc报错error: missing binary operator before token "("
  • ¥15 JSzip压缩文件时如何设置解压缩密码