FPGA——zhixin培训 Day_07——按键消抖

A.按键消抖

一、设计背景:

在用机械按键进行操作时候,按键过程会有抖动,即出现不稳定状态,因此需要按键消抖。一般经验值是10ms。

FPGA——zhixin培训 Day_07——按键消抖

二、设计需求:

设计使用尖峰脉冲信号作为按键稳定的标志信号(flag),通过仿真看到按键消抖的功能。

三、设计方案:

FPGA——zhixin培训 Day_07——按键消抖

FPGA——zhixin培训 Day_07——按键消抖

FPGA——zhixin培训 Day_07——按键消抖

五、代码

状态机:

FPGA——zhixin培训 Day_07——按键消抖

FPGA——zhixin培训 Day_07——按键消抖

六、仿真验证:

编写tb文件模拟按键,设置cnt_num为4。即/*cnt_num(4)*/也就是在50Hz时钟下,100ns可以就可使按键稳定,如下

FPGA——zhixin培训 Day_07——按键消抖

FPGA——zhixin培训 Day_07——按键消抖

练习:

用一个按键控制数码管显示,数码管显示的数值就是按键的次数,没按一次,数码管显示的数字加一,数值从0-f循环显示

代码:

顶层:

//顶层

module key_filter_seg_top(clk,rst_n,key_in,sel,seg);

 

       input clk;

       input rst_n;

       input key_in;

      

       output  [2:0]sel;

       output  [7:0]seg;

      

       wire flag;

 

       filter  /*#(.cnt_num(4)) */  filter_inst(

              .clk(clk),

              .rst_n(rst_n),

              .key_in(key_in),

              .flag(flag)

       );

       key_filter_seg key_filter_seg_inst(

              .clk(clk),

              .rst_n(rst_n),

              .flag(flag),

              .sel(sel),

              .seg(seg)

       );

endmodule

子模块代码:

//按键消抖模块:利用尖峰脉冲信号来对按键的动作中作一次处理

module filter(clk,rst_n,key_in,flag);

 

       input clk;

       input rst_n;

       input key_in;

      

       output reg flag;//输出的尖峰脉冲信号(按键稳定的标志信号)

 

       reg[31:0] cnt;

       reg state;//状态寄存器:两个状态(按下和抬起)

      

       `define s0 1'b0

       `define s1 1'b1

             

       parameter cnt_num = 50_000_000/100-1;

      

       always @(posedge clk or negedge rst_n)

              begin

                     if(!rst_n)

                            begin

                                   cnt <= 32'b0;

                                   state <= `s0;

                                   flag <= 1'b0;

                            end

                     else

                            begin

                                   case(state)

                                          `s0:begin

                                                               if(!key_in )//有按键按下

                                                                      begin

                                                                             if(cnt < cnt_num)//未达到消抖时间

                                                                                    begin

                                                                                           cnt <= cnt + 1'b1;

                                                                                           flag <= 1'b0;

                                                                                    end

                                                                             else//达到消抖时间

                                                                                    begin

                                                                                           cnt <= 32'b0;

                                                                                           flag <= 1'b1;

                                                                                           state <= `s1;

                                                                                    end

                                                                      end

                                                               else //没有按键按下

                                                                      begin

                                                                             state <= `s0;//等待按键按下

                                                                             cnt <= 32'b0;

                                                                             flag <= 1'b0;

                                                                      end

                                                  end

                                          `s1:begin

                                                                      flag <= 1'b0;

                                                                      if(key_in)//按键抬起

                                                                             begin

                                                                                    if(cnt < cnt_num)//没有到达消抖时间

                                                                                           begin

                                                                                                  cnt <= cnt + 1'b1;

                                                                                                  flag <= 1'b0;

                                                                                           end

                                                                                    else//到达消抖时间

                                                                                           begin

                                                                                                  cnt <= 32'd0;

                                                                                                  flag <= 1'b0;

                                                                                                  state <= `s0;

                                                                                           end

                                                                             end

                                                                      else//按键未抬起

                                                                             begin

                                                                                    state <= `s1;//等待按键抬起

                                                                             end

                                                   end    

                                          default : state <= `s0;

                                   endcase

                            end

              end

endmodule

数码管点亮模块:

module key_filter_seg(clk,rst_n,flag,sel,seg);

 

       input clk;

       input rst_n;

       input flag;

      

       output  [2:0]sel;

       output reg [7:0]seg;

      

       reg [3:0] key_cnt;

      

       always @(posedge clk or negedge rst_n)

              begin

                     if(!rst_n)

                            begin

                                   key_cnt <= 4'b0;

                            end

                     else

                            begin

                                   if(flag)

                                          begin

                                                 if(key_cnt <4'd15)

                                                        begin

                                                               key_cnt <= key_cnt + 1'b1;

                                                        end

                                                 else

                                                        begin

                                                               key_cnt <= 4'd0;

                                                        end

                                          end

                                   else

                                          begin

                                                 key_cnt <= key_cnt;

                                          end

                            end

              end

      

assign sel = 3'd1;

      

       always @(*)

              begin

                     if(!rst_n)

                            begin

                                   seg = 8'b1100_0000;

                            end

                     else

                            begin

                                   case(key_cnt)

                                          4'd  0: seg = 8'b1100_0000;              //“0”

                                      4'd  1: seg = 8'b1111_1001;         //“1”

                                      4'd  2: seg = 8'b1010_0100;         //“2”

                                      4'd  3: seg = 8'b1011_0000;         //“3”

                                      4'd  4: seg = 8'b1001_1001;         //“4”

                                      4'd  5: seg = 8'b1001_0010;         //“5”

                                      4'd  6: seg = 8'b1000_0010;         //“6”

                                      4'd  7: seg = 8'b1111_1000;         //“7”

                                      4'd  8: seg = 8'b1000_0000;         //“8”

                                      4'd  9: seg = 8'b1001_1000;         //“9”

                                      4'd10: seg = 8'b1000_1000;           //“A”

                                      4'd11: seg = 8'b1000_0011;           //“b”

                                      4'd12: seg = 8'b1100_0110;           //"C"

                                      4'd13: seg = 8'b1010_0001;           //"d"

                                      4'd14: seg = 8'b1000_0110;           //"E"

                                      4'd15: seg = 8'b1000_1110;           //"F"

                                   endcase

                            end

              end 

endmodule

仿真验证:

`timescale 1ns/1ns

 

module tb_key_filter_seg_top();

 

       reg clk;

       reg rst_n;

       reg key_in;

      

       wire  sel;

       wire  [7:0]seg;

      

       key_filter_seg_top key_filter_seg_top_inst(

              .clk(clk),

              .rst_n(rst_n),

              .key_in(key_in),

              .sel(sel),

              .seg(seg)

       );

       initial

              begin

                     clk = 1;

                     rst_n = 0;

                     key_in = 1;//抬起

                     #100

                     rst_n = 1;

                     #100

                     key_in = 0;//按下

                     #80

                     key_in = 1;//抬起

                     #100

                     key_in = 0;//按下(有效第一次)

                     #120

                     key_in = 1;//抬起

                     #200

                    

                     key_in = 0;//按下(有效第二次)

                     #160

                     key_in = 1;//抬起

                     #240

                     $stop;

              end

       always #10 clk = ~clk;

endmodule

FPGA——zhixin培训 Day_07——按键消抖

下板与仿真相符。