tag 标签: 按键消抖

相关博文
  • 热度 4
    2016-5-19 15:28
    3208 次阅读|
    4 个评论
    关于时钟计数器模块, 实现功能时钟计数: 毫秒,秒,分钟.....计数满清零 使用BCD计数,进位加一 按键控制(消抖模块),分频(时钟基准10hz,数码管扫描时钟400hz),计时累加模块 使用同一按键表示(开始,停止,清零)三种功能.同样,可以使用不同的按键控制,个人实现 扩展:可加入定时功能,通过设定的时间蜂鸣器响 操作平台:小梅哥"芯航线"板卡 效果: 设计RTL视图如下   分开截图了  整体好像太大了图片............. 设计基本都是以前笔记实现的模块进行累加的,关于按键消逗,分频,BCD计数,数码管不了解的都可以查看以前的笔记......这里不废话了 部分代码: 同一按键控制3个功能: ctrl模块: reg ctrl_state; always@(posedge sys_clk or negedge rst_n) if(!rst_n)begin clear = 1'b0; count = 1'b0; stop = 1'b0; ctrl_state = 2'd0; end else if(ButtonSig ctrl_state == 2'd0)begin//清零 clear = 1'b1; ctrl_state = 2'd1; end else if(ButtonSig ctrl_state == 2'd1)begin//使能计数 count = 1'b1; ctrl_state = 2'd2; end else if(ButtonSig ctrl_state == 2'd2)begin//停止计数 stop = 1'b1; ctrl_state = 2'd0; end else begin//无按键状态 clear = 1'b0; count = 1'b0; stop = 1'b0; ctrl_state = ctrl_state; end timer模块: //计数器状态转换 always@(posedge sys_clk or negedge rst_n) if(!rst_n) timer_state = 2'b00; else if(count) //使能计数 timer_state = 2'b01; else if(stop) //停止计数 timer_state = 2'b10; else timer_state = timer_state; 计数累加模块: //根据计数器状态设置来选择是否输入计数使能信号 assign cin_0_1 = (timer_state == 2'b01)?En:1'b0; BCD_Counter #( .Conuter_Top(4'd9) ) BCD_Counter_0_1( .sys_clk(sys_clk), .rst_n(rst_n), .cin(cin_0_1), .clr(clr), .cout(cout_0_1), .q(q_0_1) ); BCD_Counter #( .Conuter_Top(4'd9) ) BCD_Counter_s_L( .sys_clk(sys_clk), .rst_n(rst_n), .cin(cout_0_1), .clr(clr), .cout(cout_s_L), .q(q_s_L) ); BCD_Counter #( .Conuter_Top(4'd5) ) BCD_Counter_s_H( .sys_clk(sys_clk), .rst_n(rst_n), .cin(cout_s_L), .clr(clr), .cout(cout_s_H), .q(q_s_H) ); BCD_Counter #( .Conuter_Top(4'd9) ) BCD_Counter_m_L( .sys_clk(sys_clk), .rst_n(rst_n), .cin(cout_s_H), .clr(clr), .cout(cout_m_L), .q(q_m_L) ); BCD_Counter #( .Conuter_Top(4'd5) ) BCD_Counter_m_H( .sys_clk(sys_clk), .rst_n(rst_n), .cin(cout_m_L), .clr(clr), .cout(cout_m_H), .q(q_m_H) ); BCD_Counter #( .Conuter_Top(4'd9) ) BCD_Counter_H( .sys_clk(sys_clk), .rst_n(rst_n), .cin(cout_m_H), .clr(clr), .cout(), .q(q_H) );    
  • 热度 19
    2016-4-18 17:39
    840 次阅读|
    0 个评论
    按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开             消抖是为了避免在按键按下或是抬起时电平剧烈抖动带来的影响 结合上节笔记的边沿检测,我们看一下按键消抖例程 代码: module Key_filter( clk, rst_n, key_in, key_flag, key_state ); input clk,rst_n; input key_in; output reg key_state;//按键状态 output reg key_flag;//按键标志输出 // localparam  // idel    = 4'b0001,  //空闲态 // filter0 = 4'b0010,  //抖动滤波 // down    = 4'b0100,  //按下稳定态 // filter1 = 4'b1000; ////////////////处理外部输入信号//////////////////////// reg key_in1,key_in2;// //外部输入的异步信号同步化 消除亚稳态 always @(posedge clk or negedge rst_n) if(!rst_n)begin key_in1 = 1'b0; key_in2 = 1'b0; end else begin key_in1 = key_in; key_in2 = key_in1; end reg key_tmp1,key_tmp2; //使用两级寄存器,边沿检测 always @(posedge clk or negedge rst_n) if(!rst_n)begin key_tmp1 = 1'b0; key_tmp2 = 1'b0; end else begin key_tmp1 = key_in2; key_tmp2 = key_tmp1; end wire p_edge,n_edge; //产生跳变沿信号 assign n_edge = !key_tmp1  key_tmp2; assign p_edge = key_tmp1  (!key_tmp2); /////////////////计数信号输出////////////////////// reg  cnt; reg en_cnt;//使能计数 always @(posedge clk or negedge rst_n) if(!rst_n) cnt = 4'd0; else if(en_cnt) cnt = cnt + 1'b1; else if(!en_cnt) cnt = 4'd0; //计数满标志 always @(posedge clk or negedge rst_n) if(!rst_n) key_flag = 1'd0; else if(cnt == 4'd9) key_flag = 1'b1; else key_flag = 1'd0; ////////////////状态机模块/////////////////////// reg  state,NS;//两段式状态机 always @(posedge clk or negedge rst_n) if(!rst_n) begin state = 4'b1; end else begin state = NS; end always @(state or n_edge or p_edge or key_flag) begin //en_cnt = 1'b0; key_state = 1'b1; case(state) 4'd1 : begin if(n_edge)begin en_cnt = 1'b1; NS = 4'd2; end else NS = 4'd1; end 4'd2 : begin if(key_flag)begin NS = 4'd3; en_cnt = 1'b0; end else NS = 4'd2; end 4'd3 : begin key_state = 1'b0; if(p_edge)begin en_cnt = 1'b1; NS = 4'd4; end else NS = 4'd3; end 4'd4 : begin if(key_flag)begin en_cnt = 1'b0; key_state = 1'b1; NS = 4'd1; end else NS = 4'd4; end default : begin NS = 4'd1; en_cnt = 1'b0; key_state = 1'b1; end endcase end endmodule `timescale 1ns/1ns `define clk_period 20 module Key_tb; reg clk; reg rst_n; reg key_in; wire key_flag; wire key_state; Key_filter key_filter0( .clk(clk), .rst_n(rst_n), .key_in(key_in), .key_flag(key_flag), .key_state(key_state) ); initial clk = 1; always #(`clk_period/2)clk = ~clk; // always @(posedge clk)//随机函数使用 // begin // #(`clk_period*100);  // key_in ={$random}%2; // end initial begin rst_n = 0; key_in = 1; #(`clk_period*5); rst_n = 1; #(`clk_period + 1); press_key; #(`clk_period*200); press_key; #(`clk_period*200); press_key; #(`clk_period*500); $stop; end   task press_key;//任务函数的使用   begin   #500 key_in = 0;   #500 key_in = 1;   #500 key_in = 0;   #500 key_in = 1;   #500 key_in = 0;   #500 key_in = 1;   #500 key_in = 0;   #500 key_in = 1;   #500 key_in = 0;   #500 key_in = 1;   #500 key_in = 0;   #500 key_in = 1;   end   endtask endmodule 仿真波形: 关于仿真模型 此时可以使用仿真模型,Augus会使用...但是讲不明白==,很伤情的    需要了解的请查看     发烧友小梅哥专版  http://bbs.elecfans.com/zhuti_fpga_1.html     视频讲的很容易懂
  • 热度 22
    2015-12-27 15:49
    1597 次阅读|
    0 个评论
    抖动的产生 通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。 抖动时间 抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。这是一个很重要的时间参数,在很多场合都要用到按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保FPGA对键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。 图1 按键抖动 FPGA内实现消抖的方法 在FPGA内实现按键消抖的方法多种多样,但是最简单的是采用移位寄存器的方法进行消抖。因为移位寄存器的方法不需要对时钟进行分频,也不需要进行延时等复杂操作,即可实现对按键边沿的检测。假设未按下时键值=1. 1、在无键按下时,移位寄存器samp 始终采集到高电平,即samp =8'b1111_1111; 2、当键按下时,samp 将采集到低电平,数据的变化方式为samp =8'b1111_1110--8'b1111_1100--8'b1111_1000-- ........——8'b0000_0000;samp =8'b1111_1110即为按键下降沿。 3、当松开按键时,samp 将重新采集到高电平,数据变化方式为samp =8'b0000_0001--8'b0000_0011-- ........--8'b1111_1111;当samp =8'b0111_1111时,即为按键上升沿。 图2 移位寄存器消抖原理图 参考Verilog代码 //模块名:EdgeDetect,边沿检测 //button:按键,无键按下时为高电平//clk:10M时钟 //rst:复位按钮,低电平有效 //rise:检测到上升沿,高电平有效,宽度为1个clk //fall:检测到下降沿,高电平有效,宽度为1个clk module EdgeDetect( input clk, input rst, input button, output reg rise, output reg fall ); reg samp;//移位寄存器采集button键值 //移位寄存器采集button信息 always@(posedge clk or negedge rst) begin if(!rst) samp=8'b1111_1111; else samp={samp ,button}; end //产生上升沿信息 always@(posedge clk or negedge rst) begin if(!rst) rise=1'b0; else if(samp==8'b1111_1110) rise=1'b1; else rise=1'b0; end //产生下降沿信息 always@(posedge clk or negedge rst) begin if(!rst) fall=1'b0; else if(samp==8'b0111_1111) fall=1'b1; else fall=1'b0; end endmodule 相关阅读: 按键消抖电路瞬态分析和设计
  • 热度 20
    2015-8-17 22:15
    1078 次阅读|
    0 个评论
    这是昨天刚刚做完的一个,小项目主要是为了练习按键消抖、数码管显示、二进制转bcd码的练习。刚开始学习FPGA,所以没事就总结一下自己的学习过程,如有不对的地方恳请大家指出来,楼主一定改正,互相学习  。项目要求:将按键的次数显示到数码管上面。本项目中的方法是我通过看李凡李老师的授课视频,还有就是自己在实践中遇到的问题,写的。在这给老师赞一个  。        拿到这个小项目的时候,我首先是哪出了笔和纸对,对我要实现的功能进行分析。该项目的总体框图如下:         图中的key_scan模块为按键扫描与消抖模块,count_key模块主要是计数按键次数的模块,bin_BCD模块实现二进制转BCD码,seg模块实现按键次数的显示(本次有6个数码管)。 接下来我首先做的是设计并分析key_scan模块,这个模块使用的按键就是我们常见的机械按键,工业上的是20ms~200ms之间,为按键按下,我的也是采用的是20ms的消抖。当按键按下的时间小于20ms为抖动,大于则表示按键按下,按键抬起的抖动时间也为20ms。接下来我画出了这个模块的状态转移图如下图: 状态转移图中的temp是用来寄存按键状态的寄存器,cunt_n则是一个计数器计数按键按下的时间。 接下来就是计数按键按下次数的模块,我是这样做的每当按键的被按下会产生一段的低电平,而我则是采集其松开时会产生一个由低到高跳变的过程,每当这个上升沿到来的时候计数器计一次数,说白了就是用key_out的充当时钟。这个模块比较简单大家就看上面的系统框图中的count_key模块的框图。 接下来就是进制转换模块了。说到这个模块的话,我要好好说说了 ,由系统框图我们也可以看出来,这个模块的输入就是计数模块的输出,而计数模块输出的数据是的二进制数,为啥位宽是20,原因是数码管显示的最大数是999999,其对应的二进制数就是二十位的。数码管输入的数据则是BCD码,所以我们在进行数码管显示之前必须先将二进制数转换为BCD码。进制转换我是看李老师的讲的逐步移位法。给大家来个例子说明一下  例如输入的二进制数是8’b1111_1111,经过逐步移位的方法最终得到的BCD码为:12’b1_0101_0101,其对应的十进制百位,十位,个位,分别是:2,5,5.这种移位的方法首先设计者必须清楚的是被转换的二进制数的位宽,和最终转换为BCD码的位宽,由于中间用到一个移位寄存器此移位寄存器的位宽等于被转的二进制数位宽加上最终转换的BCD码的位宽。所以本例中的移位寄存器位宽为20,采用这种方法移位的此处比位修正的次数多一次,即就是最后一次只进行移位操作,而不进行位修正计数(每位所对应的4位BCD码如果大于四必须进行加三操作)。应用这种方法移完即可得到对应的BCD码。本例子的以为过程及修正如下表所示: 通过这个例子大家应该对二进制转BCD有一定的了解,下来进入我们的正题,我输入的是20位的二进制数,6个数码管显示的话要24为BCD码,所以我需要的移位寄存器的位宽为44.整个的转换过程是先进行移位操作最后进行位修正操作。这个模块我将他们独立出来:移位为一个模块bcd_modify,未修正为一个模块bcd_sigle_modify。下面是我的这两个模块的框图: 接下来设计最后一个模块的设计数码管显示模块的设计。本次设计采用的是共阳极数码管,故当有低电平时对应的数码管的段会点亮。数码管分位选和片选,位选顾名思义就是控制那个数码管进行显示,而片选则是存有显示数据。数码管显示部分,我采用的是1khz的时钟,如果时钟过快,数码管会显示常亮状态。数码管显示的数据要进行数码管译码操作。故可以总结为:此模块要做分频,位选的控制,还有数据的译码这几部分。我用的是以前做数码管显示是的一个现成的程序,所以这部分的程序是在一个模块下写的. 下来是是我的测试波形图的代码:   有仿真波形可以看出设计符合要求,按键在经过10个时钟周期仍保持低电平,所以说明是真实的按键按下;计数模块的仿真,当输入的key_out出现上升沿是计数器计一次数.bin-bcd转换模块从仿真波形也可以分析符合要求.数码管显示模块也一样.不过在测试时key_scan模块中的按键检测时间需要改为10,不然仿真波形看不到结果,下板需要改为1000000. 此设计的代码,链接:http://pan.baidu.com/s/1bn9D2DD 密码:byvb 第一次发这种学习贴,希望大家能指出我的不足,博主一定改正,谢谢了。 作者:会飞的小鸟
  • 热度 32
    2015-3-22 18:04
    7490 次阅读|
    0 个评论
    抖动的产生 通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。 抖动时间 抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。这是一个很重要的时间参数,在很多场合都要用到按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保FPGA对键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。 图1 按键抖动 FPGA内实现消抖的方法 在FPGA内实现按键消抖的方法多种多样,但是最简单的是采用移位寄存器的方法进行消抖。因为移位寄存器的方法不需要对时钟进行分频,也不需要进行延时等复杂操作,即可实现对按键边沿的检测。假设未按下时键值=1. 1、在无键按下时,移位寄存器samp 始终采集到高电平,即samp =8'b1111_1111; 2、当键按下时,samp 将采集到低电平,数据的变化方式为samp =8'b1111_1110--8'b1111_1100--8'b1111_1000-- ........——8'b0000_0000;samp =8'b1111_1110即为按键下降沿。 3、当松开按键时,samp 将重新采集到高电平,数据变化方式为samp =8'b0000_0001--8'b0000_0011-- ........--8'b1111_1111;当samp =8'b0111_1111时,即为按键上升沿。 图2 移位寄存器消抖原理图 参考Verilog代码 //模块名:EdgeDetect,边沿检测 //button:按键,无键按下时为高电平//clk:10M时钟 //rst:复位按钮,低电平有效 //rise:检测到上升沿,高电平有效,宽度为1个clk //fall:检测到下降沿,高电平有效,宽度为1个clk module EdgeDetect( input clk, input rst, input button, output reg rise, output reg fall ); reg samp;//移位寄存器采集button键值 //移位寄存器采集button信息 always@(posedge clk or negedge rst) begin if(!rst) samp=8'b1111_1111; else samp={samp ,button}; end //产生上升沿信息 always@(posedge clk or negedge rst) begin if(!rst) rise=1'b0; else if(samp==8'b1111_1110) rise=1'b1; else rise=1'b0; end //产生下降沿信息 always@(posedge clk or negedge rst) begin if(!rst) fall=1'b0; else if(samp==8'b0111_1111) fall=1'b1; else fall=1'b0; end endmodule 相关阅读: 按键消抖电路瞬态分析和设计
相关资源