tag 标签: 独立按键

相关博文
  • 热度 16
    2014-12-27 14:57
    1538 次阅读|
    0 个评论
    图中存在较多的模块,因此在此将每个模块的功能做简单介绍:       normal_keys_detect 独立按键消抖模块 Dig_Led_Driver 数码管驱动模块 Clock_Control 时钟控制模块 Bin_to_BCD 二进制转 BCD 格式模块,将时、分、秒计数器的值转换为 BCD 格式,以送往数码管显示 MUX 最右侧三个多路选择器负责根据时分秒的显示使能信号进行对应数码管位的亮灭控制 表 4-3 数字钟实验模块功能说明 另外, Clock_Control 模块为综合模块,内部包含了时、分、秒、时钟计数器模块和时间设定模块,该模块的内部结构这里小梅哥不做过多介绍,详细请参看代码。 五、 代码组织方式 本实验主要学习由顶向下的设计流程,代码均为常见风格,这里不多做介绍。希望读者能够通过代码架构,学习领会这种自顶向下的设计结构的优势。 六、 关键代码解读 本设计中,顶层模块主要实现了各个模块的例化和数码管显示使能的多路控制,相信看了图 4-1 后,便能理解顶层代码的含义。由于本系统涉及到的模块较多,采用文档的形式很难简洁的讲解清楚,因此,综合实验,小梅哥以后将不再进行关键代码的解读。反之,小梅哥会尽快进行视频的录制,对综合实验采用视频的方式讲解,以使读者快速理解架构。 七、 测试平台设计 本系统为低速系统,采用 Modelsim 仿真耗时长,而且波形不便于观察。因此仿真略去。大家可以对每个子模块进行仿真,以验证其正确性。 八、 仿真分析 九、 下板验证 此次,小梅哥采用很早以前购买的 21EDA 的板子进行了下板测试,实测功能完备。以下为测试照片(渣渣像素,请各位谅解)。 十 、 总结 本实验实现了数码钟的功能,并可以通过 4 个按键进行时间的设置,因为时间的关系,小梅哥没有在文档中进行详细的介绍,请大家谅解。
  • 热度 19
    2014-10-30 09:54
    1726 次阅读|
    1 个评论
    一、         实验目的 实现数码时钟的功能,要求能够进行 24 时制时、分、秒的显示,并能够通过按键调整时间。 二、         实验原理 通过对系统时钟进行计数,获得 1S 的标准信号,再以该信号为基础,进行时、分、秒的计数,通过数码管将该计数值显示出来,即可实现数字钟的功能。同时可以使用独立按键对时、分、秒计数器的初始值进行设置,即可实现时间的设定。 三、         硬件设计 本实验硬件电路简单,用到了 8 个数码管和 4 个独立按键。硬件电路如下:     图 3-1 数字钟电路   四、         架构设计 本实验设计架构模块较多,下图为数字钟的架构:   图 4-1 数字钟实验模块组织结构图 由图可知本实验有 16 个输出端口和 6 个输入端口,各端口的意义如下 端口说明 端口名 端口功能或意义 Rst_n 全局复位 Clk 系统时钟输入端口 Key_in 按键输入端口 Seg 数码管段驱动输出 Sel 数码管位驱动输出 表 4-1 数字钟实验端口说明 因为存在模块间的连接,因此有部分内部信号,下表为部分内部信号的名称和功能说明 内部信号说明 内部信号名 内部信号功能或意义 Time_Data 时间值,直接送往数码管显示 Key_Value 按键检测结果输出 Key_Flag 按键检测成功标志信号 Hour_Disp_en 数码管“时”显示使能信号,提供调时时候的闪烁效果 Min_Disp_en 数码管“分”显示使能信号,提供调分时候的闪烁效果 Sec_Disp_en 数码管“秒”显示使能信号,提供调秒时候的闪烁效果 表 4-2 数字钟实验内部信号说明      
  • 热度 22
    2014-10-27 14:17
    1729 次阅读|
    2 个评论
    八、 仿真分析   由上图仿真结果可知,当有按键按下时,需要较长一段时间后, Key_Flag 会有一个高电平脉冲,同时 Key_Value 更新为输入按键的反码。 为了确定消抖是成功的,这里再附上按键松开时的抖动细节图:   由图可知,松开按键时,该按键 IO 不断的检测到高电平和低电平,直到一段时间和,抖动方停止,稳定为按键没有按下时的状态 下图为整个工程的仿真结果,由图可知,每按下一次按键 0 ( key_in ) ,led 的状态便翻转一次。     九、 下板验证 手头暂无开发板,板级验证略。   十、 总结 本文档对按键消抖的原理进行了分析,并对消抖核心模块的设计进行了仿真,通过 modelsim 仿真验证了消抖模块设计的正确性。 具体的控制模块这里因为篇幅和时间关系暂不介绍,也因为没有开发板,暂时无法录制演示视频,等录制视频时,我会对整个系统的架构设计,代码设计进行详细的分析和讲解。以前没有做过不知道,写了两三次后才发现,原来文档的编写和整理比编写代码要的时间要多的多。不过,我总还是会坚持做下去的,希望我能有足够的时间来做这些事。
  • 热度 20
    2014-10-27 14:16
    2189 次阅读|
    3 个评论
        几乎没有哪一个系统没有输入输出设备,大到显示器,小到 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_in;    output reg Key_Flag;  output reg Key_Value;  reg key_tmp,key_tmp1;  reg 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 Key_in;    wire Key_Flag;  wire 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 Key;   begin    Key_in = 4'b1111;        /*按下抖动*/    #100 Key_in = 0;    #200 Key_in = 1;    #300 Key_in = 0;    #400 Key_in = 1;    #500 Key_in = 0;    #600 Key_in = 1;    #700 Key_in = 0;    #800 Key_in = 1;    #900 Key_in = 0;        /*稳定期*/    #22000000;        /*释放抖动*/    #100 Key_in = 1;    #200 Key_in = 0;    #300 Key_in = 1;    #400 Key_in = 0;    #500 Key_in = 1;    #600 Key_in = 0;    #700 Key_in = 1;    #800 Key_in = 0;    #900 Key_in = 1;   end  endtask endmodule   testben 中使用了一个任务( task ),该任务模拟按键抖动的过程,给按键按下和释放时增加抖动,调用时只需要输入需要按下的按键编号,该任务便可自动完成按下抖动、稳定、松开抖动的过程。 整个工程的 testbench 与消抖模块的 testbench 一样,只需要在例化部分将消抖模块替换为顶层模块即可,同时将每个按键的任务由一次调用该为两次调用即可,详细代码如下: 以下是代码片段: `timescale 1ns/1ns module top_tb;  reg Clk;  reg Rst_n;  reg Key_in;    wire 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 Key;   begin    Key_in = 4'b1111;        /*按下抖动*/    #100 Key_in = 0;    #200 Key_in = 1;    #300 Key_in = 0;    #400 Key_in = 1;    #500 Key_in = 0;    #600 Key_in = 1;    #700 Key_in = 0;    #800 Key_in = 1;    #900 Key_in = 0;        /*稳定期*/    #22000000;        /*释放抖动*/    #100 Key_in = 1;    #200 Key_in = 0;    #300 Key_in = 1;    #400 Key_in = 0;    #500 Key_in = 1;    #600 Key_in = 0;    #700 Key_in = 1;    #800 Key_in = 0;    #900 Key_in = 1;   end  endtask endmodule
相关资源