FPGA之旅设计99例之第二例-----按键

简介: 笔记

一.简介


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


欢迎关注微信公众号 FPGA之旅 哦

可以在上面联系,有什么问题的话


二. 按键电路


按键为输入设备,通过电路图可以知道,当按键按下的时候,FPGA会检测到低电平,按键没有按下的时候,FPGA检测到的是高电平。

1.png

三. 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;
    end
endmodule


当按键按下后,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;
  end
end
always@(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;
  endcase
end
//延时计数
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/1ps
module 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


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

2.png

公众号:FPGA之旅


目录
相关文章
|
5月前
|
异构计算
FPGA新起点V1开发板(十)——按键控制LED
FPGA新起点V1开发板(十)——按键控制LED
FPGA新起点V1开发板(十)——按键控制LED
|
异构计算
|
异构计算
实验二 基于FPGA的分频器的设计(基本任务:设计一个分频器,输入信号50MHz,输出信号频率分别为1KHz、500Hz及1Hz。拓展任务1:用按键或开关控制蜂鸣器的响与不响。拓展任务2:用按键或开)
实验二 基于FPGA的分频器的设计(基本任务:设计一个分频器,输入信号50MHz,输出信号频率分别为1KHz、500Hz及1Hz。拓展任务1:用按键或开关控制蜂鸣器的响与不响。拓展任务2:用按键或开)
1312 0
实验二 基于FPGA的分频器的设计(基本任务:设计一个分频器,输入信号50MHz,输出信号频率分别为1KHz、500Hz及1Hz。拓展任务1:用按键或开关控制蜂鸣器的响与不响。拓展任务2:用按键或开)
|
异构计算
FPGA-基于UART的QVGA显示(二)(实现PC端发送字母数字汉字的分别显示通过按键可以删除字符)
FPGA-基于UART的QVGA显示(二)(实现PC端发送字母数字汉字的分别显示通过按键可以删除字符)
126 0
FPGA-基于UART的QVGA显示(二)(实现PC端发送字母数字汉字的分别显示通过按键可以删除字符)
FPGA-状态机的实现实例(按键的消抖)
FPGA-状态机的实现实例(按键的消抖)
226 0
|
C语言 异构计算
FPGA-独立按键的消抖(软件消抖未用状态机)
FPGA-独立按键的消抖(软件消抖未用状态机)
376 0
|
存储 编解码 监控
案例分享:Qt+Arm+Fpga医疗肾镜(又名内窥镜)(实时影像、冻结、拍照、白平衡、九宫格、录像、背光调整、硬件光源调整、光源手动自动调整、物理按键)
案例分享:Qt+Arm+Fpga医疗肾镜(又名内窥镜)(实时影像、冻结、拍照、白平衡、九宫格、录像、背光调整、硬件光源调整、光源手动自动调整、物理按键)
案例分享:Qt+Arm+Fpga医疗肾镜(又名内窥镜)(实时影像、冻结、拍照、白平衡、九宫格、录像、背光调整、硬件光源调整、光源手动自动调整、物理按键)
|
异构计算
【黑金ZYNQ7000系列原创视频教程】06.ZYNQ来自FPGA的中断&mdash;&mdash;按键中断实验
黑金论坛地址: http://www.heijin.org/forum.php?mod=viewthread&tid=36640&extra=page%3D1   爱奇艺地址: http://www.iqiyi.com/w_19rugglzn1.html?source=
1935 0
|
异构计算
FPGA按一下按键,对应端口输出单个脉冲
对于FPGA的verilog语言,,,规定一个变量不能在多个always中被赋值.但是可以在多个alway块中做判断--结合状态机思想 module state(key,led,clk); input key;//输入按键 input clk;//输入时钟48M output reg...
1174 0