新闻中心

EEPW首页 > 嵌入式系统 > 牛人业话 > 小梅哥和你一起深入学习FPGA之独立按键检测(上)

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

作者:时间:2015-03-28来源:网络收藏

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

本文引用地址:http://www.amcfsurvey.com/article/271738.htm

  一、 实验目的

  实现4个独立按键的抖动检测实验,并通过4个独立按键控制4个led灯亮灭状态的翻转。

  二、 实验原理

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

  

 

  图2-1 轻触按键实物图

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

  

 

  因此,我们所需要做的工作,就是滤除按键按下和释放时各存在的20ms的不稳定波形

  三、 硬件设计

  独立按键属于一种输入设备,其与连接的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

fpga相关文章:fpga是什么


可控硅相关文章:可控硅工作原理


比较器相关文章:比较器工作原理


led显示器相关文章:led显示器原理


上拉电阻相关文章:上拉电阻原理


关键词: FPGA 按键检测

评论


相关推荐

技术专区

关闭