您的位置 首页 厂商

小梅哥和你一同深化学习FPGA之独立按键检测(上)

几乎没有哪一个系统没有输入输出设备,大到显示器,小到led灯,轻触按键。作为一个系统,要想稳定的工作,输入输出设备的性能占了很重要的角色。本实验,小梅哥就通过一个独立按键的检测实验,来正式步入基本

  几乎没有哪一个体系没有输入输出设备,大到显示器,小到led灯,轻触按键。作为一个体系,要想安稳的作业,输入输出设备的功能占了很重要的人物。本试验,小梅哥就经过一个独立按键的检测验验,来正式步入根本外设驱动开发的大门。

  一、 试验意图

  完结4个独立按键的颤动检测验验,并经过4个独立按键操控4个led灯亮灭状况的翻转。

  二、 试验原理

  实践体系中常用的按键大部分都是轻触式按键,如图2-1所示。该按键内部由一个弹簧片和两个固定触点组成,当弹簧片被按下,则两个固定触点接通,按键闭合。弹簧片松开,两个触点断开,按键也就断开了。依据这种按键的机械特性,在按键按下时,会先有一段时刻的不安稳期,在这期间,两个触点时而接通,时而断开,咱们称之为颤动,当按键大约按下20ms后,两个触点才干处于安稳的闭合状况,按键松开时和闭合时状况相似。而咱们的FPGA作业在很高的频率,按键接通或断开时任何一点小的颤动都能容易的捕捉到,假如不加区分的将每一次闭合或断开都作为一次按键事情,那么必然一次按键动作会被FPGA识别为很屡次按键操作,然后导致体系作业安稳性下降。

  

 

  图2-1 轻触按键实物图

  一次按键动作的大致波形如下图所示:

  

 

  因而,咱们所需要做的作业,便是滤除按键按下和开释时各存在的20ms的不安稳波形

  三、 硬件规划

  独立按键归于一种输入设备,其与FPGA衔接的IO口被接上了10K的上拉电阻,在按键没有按下时,FPGA会检测到高电平;当按键按下后,FPGA的IO口上则将出现低电平。因而,按键检测的本质便是读取FPGA的IO上的电平。

  

 

  图3-1 独立按键典型电路

  四、 架构规划

  本试验由一共四个模块组成,分别为LED驱动模块、独立按键检测模块、操控模块和顶层模块,其架构如下:

  

 

  

 

  以下为按键颤动检测的代码,选用状况机的方法编写,一共有两个状况,按下消抖为状况0,开释消抖为状况1。具体的消抖流程代码中的注释现已写的比较清楚,但假如悉数用文字解说出来仍是有必定的复杂性。这也是实地解说和网上文档的一点点距离吧,期望我后期的视频里边能讲清楚。其实颤动消除的中心思路便是对按键状况的改动进行计时,若两次电平改动之间时刻小于20ms,则视为颤动,若低电平安稳时刻超越20ms,则标明检测到了安稳的按键状况。开释时的消抖进程与按下时的消抖进程相似。

  以下是代码片段:

  module normal_keys_detect #(parameter KEY_WIDTH = 4)

  (Clk,Rst_n,Key_in,Key_Flag,Key_Value);

  input Clk;

  input Rst_n;

  input [KEY_WIDTH-1:0]Key_in;

  output reg Key_Flag;

  output reg[KEY_WIDTH-1:0]Key_Value;

  reg [KEY_WIDTH-1:0]key_tmp,key_tmp1;

  reg [19:0]cnt1;

  reg state;

  wire level_change; /*按键状况改动标志信号*/

  localparam cnt1_TOP = 1_000_000;

  /*——-存储按键状况的上一个状况—————*/

  always @ (posedge Clk or negedge Rst_n)

  begin

  if(!Rst_n)

  begin

  key_tmp <= ‘d0;

  key_tmp1 <= ‘d0;

  end

  else

  begin

  key_tmp <= Key_in;

  key_tmp1 <= key_tmp;

  end

  end

  /*—经过比较按键上一个状况和此时刻状况来获悉按键状况是否改动—*/

  assign level_change = (key_tmp == key_tmp1)?1’b0:1’b1;

  always @ (posedge Clk or negedge Rst_n)

  if(!Rst_n)

  begin

  cnt1 <= 20’d0;

  state <= 1’b0;

  Key_Value <= 4’b0000;

  Key_Flag <= 1’b0;

  end

  else

  begin

  case(state)

  0: /*按下检测*/

  //没有电平改动,且按键输入状况不全为1

  if(!level_change & key_tmp1 != {KEY_WIDTH{1’b1}})

  begin

  if(cnt1 == cnt1_TOP)/*计数满消抖所需时刻*/

  begin

  Key_Value <= ~Key_in;

  Key_Flag <= 1;

  cnt1 <= 0;

  state <= 1;

  end

  else

  cnt1 <= cnt1 + 1’b1;

  end

  else

  begin

  cnt1 <= 0;

  Key_Flag <= 0;

  state <= 0;

  end

  1:/*开释检测*/

  begin

  Key_Flag <= 0;

  /*没有电平改动,且按键输入状况全为1*/

  if(!level_change & key_tmp1 == {KEY_WIDTH{1’b1}})

  begin

  if(cnt1 == cnt1_TOP)/*计数满消抖所需时刻*/

  begin

  cnt1 <= 0;

  state <= 0;

  end

  else

  cnt1 <= cnt1 + 1’b1;

  end

  else

  begin

  cnt1 <= 0;

  state <= 1;

  end

  end

  endcase

  end

  endmodule

  七、 测验渠道规划

  本试验主要对按键检测的成果进行调查和剖析,经过仿真,验证规划的正确性和合理性。按键消抖模块的testbench的代码如下:

  以下是代码片段:

  `timescale 1ns/1ns

  module normal_keys_detect_tb;

  reg Clk;

  reg Rst_n;

  reg [3:0]Key_in;

  wire Key_Flag;

  wire [3:0]Key_Value;

  normal_keys_detect

  #(

  .KEY_WIDTH(4)

  )

  normal_keys_detect_inst1(

  .Clk(Clk),

  .Rst_n(Rst_n),

  .Key_in(Key_in),

  .Key_Flag(Key_Flag),

  .Key_Value(Key_Value)

  );

  initial begin

  Clk = 1;

  Rst_n = 0;

  Key_in = 4’b1111;

  #100;

  Rst_n = 1;

  press_key(0);

  #30000000;

  press_key(1);

  #30000000;

  press_key(2);

  #30000000;

  press_key(3);

  #30000000;

  $stop;

  end

  always #10 Clk = ~Clk;

  task press_key;

  input [1:0]Key;

  begin

  Key_in = 4’b1111;

  /*按下颤动*/

  #100 Key_in[Key] = 0;

  #200 Key_in[Key] = 1;

  #300 Key_in[Key] = 0;

  #400 Key_in[Key] = 1;

  #500 Key_in[Key] = 0;

  #600 Key_in[Key] = 1;

  #700 Key_in[Key] = 0;

  #800 Key_in[Key] = 1;

  #900 Key_in[Key] = 0;

  /*安稳期*/

  #22000000;

  /*开释颤动*/

  #100 Key_in[Key] = 1;

  #200 Key_in[Key] = 0;

  #300 Key_in[Key] = 1;

  #400 Key_in[Key] = 0;

  #500 Key_in[Key] = 1;

  #600 Key_in[Key] = 0;

  #700 Key_in[Key] = 1;

  #800 Key_in[Key] = 0;

  #900 Key_in[Key] = 1;

  end

  endtask

  endmodule

  testben中使用了一个使命(task),该使命模仿按键颤动的进程,给按键按下和开释时添加颤动,调用时只需要输入需要按下的按键编号,该使命便可主动完结按下颤动、安稳、松开颤动的进程。

  整个工程的testbench与消抖模块的testbench相同,只需要在例化部分将消抖模块替换为顶层模块即可,一起将每个按键的使命由一次调用该为两次调用即可,具体代码如下:

  以下是代码片段:

  `timescale 1ns/1ns

  module top_tb;

  reg Clk;

  reg Rst_n;

  reg [3:0]Key_in;

  wire [3:0]Led;

  top top_inst(

  .Clk(Clk),

  .Rst_n(Rst_n),

  .Key_in(Key_in),

  .Led(Led)

  );

  initial begin

  Clk = 1;

  Rst_n = 0;

  Key_in = 4’b1111;

  #100;

  Rst_n = 1;

  press_key(0);

  #30000000;

  press_key(0);

  #30000000;

  press_key(1);

  #30000000;

  press_key(1);

  #30000000;

  press_key(2);

  #30000000;

  press_key(2);

  #30000000;

  press_key(3);

  #30000000;

  press_key(3);

  #30000000;

  $stop;

  end

  always #10 Clk = ~Clk;

  task press_key;

  input [1:0]Key;

  begin

  Key_in = 4’b1111;

  /*按下颤动*/

  #100 Key_in[Key] = 0;

  #200 Key_in[Key] = 1;

  #300 Key_in[Key] = 0;

  #400 Key_in[Key] = 1;

  #500 Key_in[Key] = 0;

  #600 Key_in[Key] = 1;

  #700 Key_in[Key] = 0;

  #800 Key_in[Key] = 1;

  #900 Key_in[Key] = 0;

  /*安稳期*/

  #22000000;

  /*开释颤动*/

  #100 Key_in[Key] = 1;

  #200 Key_in[Key] = 0;

  #300 Key_in[Key] = 1;

  #400 Key_in[Key] = 0;

  #500 Key_in[Key] = 1;

  #600 Key_in[Key] = 0;

  #700 Key_in[Key] = 1;

  #800 Key_in[Key] = 0;

  #900 Key_in[Key] = 1;

  end

  endtask

  endmodule

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/116702.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部