如何设计一个实用的按键模块

描述

一.简介

这是FPGA之旅的第二个设计实例了,按键在项目中的作用是非常大的,使用的很频繁,本例将带大家设计一个实用的按键模块。

二. 按键威廉希尔官方网站

按键为输入设备,通过威廉希尔官方网站 图可以知道,当按键按下的时候,FPGA会检测到低电平,按键没有按下的时候,FPGA检测到的是高电平。

代码

三. Verilog代码编写

直接来一段最简单的按键检测的代码编写,都不用仿真。

按键按下,LED灯状态取反。

 

module KEY(  input    clk,    input    rst_n,    input    key,    output  reg  led);    always@(posedge clk or negedge rst_n)    begin        if(rst_n == 1'b0)             led <= 1'b0;        else if(key == 1'b0)            led <= ~led;        else            led <= led;    endendmodule 

 

当按键按下后,LED的状态取反,这个在仿真的时候是可以看到变化的,但是实际上板测试的话,是没有效果的,因为clk的时钟周期一般为20ns,每次按键按下的持续时间可以达到ms以上,所以LED会多次取反,所以这么简单粗暴是不可以的,需要我们做一些额外处理。此外在按键按下的瞬间,电平会出现不稳定的情况,也需要进行处理。解决这些问题,正是这个例程的重点。

四. 解决方案设计

按键按下的时候,一共有两个问题

    电平不稳定

    短时间内重复检测

第一个问题可以通过按键消抖来解决,第二个问题,可以在按键消抖的基础上,增加一些判断来解决,于是就有了以下三种模式

模式一,按下生效,释放,算一次

模式二,按下,释放生效,算一次

模式三,按下,一段时间算一次

这里通过状态机的方式来实现,第一步就是要分析一共有几个状态。

空闲态:按键没有按下时,所处的状态。

消抖态:   按键按下后,进入消抖态,在此期间,如果按键释放了的话,回到空闲态,否则进入延时态。

延时态:延时,直到按键释放。

释放态:按键释放,回归到空闲态。

模式一,可以在消抖态完成后,生效。

模式二,可以在释放态,生效。

模式三,可以在延时态,生效。

完美,这不就全部都解决了嘛! 代码如下。

 

//按键消抖module btn_dis_shake(        input      clk,  input      rst_n,    input      ikey,        //按键输入  output      okey        //按键输出);//模式//0   按下生效,抬起,算一次//1   按下抬起,算一次//2  按下后,一段时间算一次parameter      mode = 2;
localparam      S_IDLE    =    'd0;localparam      S_DIS_SHAKE =       'd1;localparam      S_DEALY    =    'd2;localparam      S_UP    =    'd3;
localparam      DIS_SHAKE  =  'd6000;    //消抖延时localparam      DELAY    =  'd50000;  //模式2中,一段时间
reg[3:0] state  ,  next_state;
wire neg_key,pos_key;  //按键下降沿上升沿reg   key0,key1;      //按键状态储存
reg[30:0]  delay_cnt;
assign    neg_key =  key1 & (~key0);    //判断按键信号的下降沿assign    pos_key  =  (~key1) & key0;    //判断按键信号的上升沿//根据模式来判断按键输出assign   okey   =  (mode == 0 &&  state == S_DIS_SHAKE && delay_cnt == DIS_SHAKE) ? 1'b1 : (mode == 1 && state == S_UP)?1'b1:(mode==2 && state == S_DEALY && delay_cnt == DELAY) ? 1'b1:1'b0;always@(posedge clk or negedge rst_n)begin  if(rst_n  == 1'b0)  begin      key0 <= 1'b1;      key1 <= 1'b1;  end  else  begin    key0 <= ikey;    key1 <= key0;  endendalways@(posedge clk or negedge rst_n)begin  if(rst_n == 1'b0)    state <= S_IDLE;  else    state <= next_state;end
always@(*)begin  case(state)    S_IDLE:      if(neg_key  ==  1'b1)        next_state <= S_DIS_SHAKE;      else        next_state <= S_IDLE;    S_DIS_SHAKE:      //按下消抖        if(delay_cnt == DIS_SHAKE)          next_state <= S_DEALY;        else if(pos_key == 1'b1)          next_state <= S_IDLE;        else          next_state <= S_DIS_SHAKE;    S_DEALY:      //延时      if(delay_cnt == DELAY  && pos_key == 1'b1)        next_state <= S_UP;      else if( pos_key == 1'b1)        next_state <= S_UP;      else        next_state <= S_DEALY;    S_UP:      next_state <= S_IDLE;    default:  next_state <= S_IDLE;  endcaseend
//延时计数always@(posedge clk or negedge rst_n)begin  if(rst_n == 1'b0)    delay_cnt <= 'd0;  else if(state != next_state)    delay_cnt  <= 'd0;  else if(state == S_DIS_SHAKE)    delay_cnt <= delay_cnt + 1'b1;  else if(state == S_DEALY && delay_cnt == DELAY)    delay_cnt <= 'd0;  else if(state == S_DEALY)    delay_cnt <= delay_cnt + 1'b1;  else    delay_cnt <= 'd0;end
endmodule 

 

代码是写完了,对不对呢 ? 上仿真!!!仿真的时候别忘记了将DIS_SHAKE这个参数调小一点了,可以设置为2就可以了,否则,你可以试试哦,就只对模式一进行仿真,其他的模式,也可以自行尝试喔!

 

`timescale  1ns/1psmodule testbeach();
    reg clk;    reg rst_n;    reg ikey;    wire okey;          always #50 clk <= ~clk;     initial begin       clk = 1'b0;       rst_n = 1'b1;       ikey = 1'b1;                #100        rst_n = 1'b0;        #100        rst_n = 1'b1;                ikey = 1'b0;  //按下        #400        ikey = 1'b1;  //释放        #200        ikey = 1'b0;  //按下        #600        ikey = 1'b1;  //释放    end
btn_dis_shake #(.mode(0))btn_dis_shakeHP(          .clk    (clk),    .rst_n  (rst_n),      .ikey    (ikey),        //按键输入    .okey  (okey)      //按键输出);    endmodule

 

当当当当!!!完美对应起来,测试通过!

代码 

      审核编辑:彭静
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分