找回密码
 注册
关于网站域名变更的通知
查看: 260|回复: 2
打印 上一主题 下一主题

特权的按键消抖的理解

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-5-17 07:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
特权的按键消抖的理解
昨天上午看的视频,特权的按键消抖,想了好久,到现在终于弄明白了,下面是我理解的方式:
5 e  A; X8 G) Q7 }, \( L% _7 D先上他的程序:, c& A4 m' v& r

  M! N' J8 p; n$ _. W- h' @module key_led(clk,rst_n,sw1_n,sw2_n,sw3_n,
. O% h8 V, u5 Y" `. A      led_d3,led_d4,led_d5,6 W. I# G* f; t% `8 x9 @
   Q1,Q2,Q3,Q4,Q5,Q62 L6 [5 V$ r5 z: w9 B
);
9 c4 d0 w! R: Ainput   clk; //主时钟信号,50MHz* c: m9 P: E% k. r4 |7 f
input   rst_n; //复位信号,低有效# B% j, p* ~/ K: H. H* @6 E, g
input   sw1_n,sw2_n,sw3_n;  //三个独立按键,低表示按下
2 p1 `, P# Y3 \5 F% f1 aoutput  led_d3,led_d4,led_d5; //发光二极管,分别由按键控制, a3 S0 Y9 _! L
output  Q1,Q2,Q3,Q4,Q5,Q6;
! |. i7 h5 p* Q* treg[2:0] key_rst; 2 p5 `! u7 K! n2 }* o  y
always @(posedge clk  or negedge rst_n)   
/ M6 u$ }5 `4 ?- o# y3 oif (!rst_n) key_rst <= 3'b111;  * [: ~( s( l% X: @) o
else key_rst <= {sw3_n,sw2_n,sw1_n};
3 N3 D* l7 Y" J3 wreg[2:0] key_rst_r;       //每个时钟周期的上升沿将key_rst信号锁存到key_rst_r- u4 [$ ~* @2 A' Z1 g: o( {- |

- D) g) S: |4 C) @5 A9 ^- K2 ]always @ ( posedge clk  or negedge rst_n )   6 N6 L5 _/ {. [# _4 s6 P
if (!rst_n) key_rst_r <= 3'b111;  / d. Y9 A' p$ {. O. ]! t% j( a
else key_rst_r <= key_rst;  
: H$ H) j. q, H2 b9 l//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期3 O; i( I, P6 n5 [7 m
wire[2:0] key_an = key_rst_r & ( ~key_rst);5 H" n) F: v, a- v7 x
reg[2:0]  cnt; //计数寄存器& k+ O9 E3 e9 j7 N% Y# a$ {
always @ (posedge clk  or negedge rst_n)  & l4 f( m, q0 Z) x6 G" a
if (!rst_n) cnt <= 3'd0; //异步复位 % `# C- r/ n! f3 ^6 r- W# }
else if(key_an) cnt <=3'd0;  4 C0 p& ]9 A9 S+ C/ L" N
else cnt <= cnt + 1'b1;! q8 U/ b0 Y5 j7 ]2 g' ?
reg[2:0] low_sw;
, n7 C& j  ^9 c) [# f+ r8 c3 ualways @(posedge clk  or negedge rst_n)   
( [& s8 J4 o2 S4 d9 X# Aif (!rst_n) low_sw <= 3'b111;    ' I' e& X5 @" s0 Q
else if (cnt == 3'd5)  //满60ns,将按键值锁存到寄存器low_sw中      
" E% d: e# U; Y) sbegin : C+ q8 x  c; H6 O
low_sw <= {sw3_n,sw2_n,sw1_n};% o; K+ x$ W) S4 C: J3 c& z
end0 l+ Z3 t, G2 {( t
reg  [2:0] low_sw_r;       //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中' S- C) S" @+ V, H: T7 G7 S, |
always @ ( posedge clk  or negedge rst_n )
% m" Z# w/ Q9 H) X" m if (!rst_n) low_sw_r <= 3'b111;
) u9 d* V  I+ z9 R3 aelse low_sw_r <= low_sw;6 B7 R5 j: Z8 `' s7 P2 O
   + K: y  c% Q# N0 M1 t/ j
//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期1 w8 b8 X3 t& _% w# a
$ @$ P  K6 `& s
wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);( u' p( n% @% R( ^: W; |/ z# W& P
reg d1;# w' l* E$ F* Z1 i
reg d2;$ `! [( d3 @2 D) S# k6 q
reg d3;: Q  d: [% S# e# n8 X) r" D
always @ (posedge clk or negedge rst_n)  , X- W7 ^& A  ~. P
if (!rst_n) begin
# |8 ^' t6 ^2 z8 {! C        d1 <= 1'b0;" x7 o# O! G) G+ Q3 B) F
        d2 <= 1'b0;
- H  o' E4 P2 O* n7 V% g! S( `        d3 <= 1'b0;" q3 ]% Q, e" u' o& }
      end   0 U& b8 {( n" [: m
else begin  //某个按键值变化时,LED将做亮灭翻转       3 h4 g2 C9 Q8 \# B+ u, T0 _
if ( led_ctrl[0] ) d1 <= ~d1; 4 @+ R) h0 W# @4 ]5 V6 N  {
        if ( led_ctrl[1] ) d2 <= ~d2;
: v1 t$ S7 B8 g+ {; A1 ^" s# f        if ( led_ctrl[2] ) d3 <= ~d3;
0 u$ |0 |: u  ?6 ~8 b5 n      end* _1 |5 `! F1 f6 X! n/ p5 `. Z
assign led_d3 = d1 ? 1'b1 : 1'b0;  //LED翻转输出
  g3 ]( P9 U1 r( Bassign led_d4 = d2 ? 1'b1 : 1'b0;: {4 P7 A3 s9 o/ x2 O
assign led_d5 = d3 ? 1'b1 : 1'b0;
0 D' w$ c. D4 f7 j# L7 D. {! qassign Q1=key_rst;' Y1 O0 Q4 I! B) F6 g2 m) `5 P
assign Q2=key_rst_r;
4 p6 e% @1 U) K& y5 h3 W4 V3 T) bassign Q3=key_an;
; e- U. A( `/ D  passign Q4=low_sw;, k- ]; {, h6 T9 C& b. e, P# F
assign Q5=low_sw_r;8 ^5 u  D7 T9 l% s" w
assign Q6=led_ctrl;
* L+ ~: ~. D3 f; K  \* i' L3 {endmodule2 C; @$ h9 f6 C% [' l5 ]1 U
1 o- Z9 }1 N5 C8 C# v
个人刚开始看这个程序,只是觉得FPGA太复杂了,一个按键消抖而已,,程序写的好复杂,寄存器也用掉了不少,不过这也是没办法的 事,入正题,
% c* P: J: T, N他的思路其实就是按键那边每来一个下降沿,有一个寄存器的值key_an就会保持一个时钟脉冲的高电平,并且这个高电平用于给延时计数器的计数清零,这种方法的好处就在于毛刺全部消失后,就是按键按下去稳定后计数器才开始计数,比较可靠,之后计数器计数到设定好时间后,判断此时的按键是否按下,若按键值为0(按键一直保持按下状态,没有抖动),则把按键值存入一个寄存器low_sw,这个寄存器之前是一直保持为1的,所以这个时候也会有一个下降沿发生,同样的道理可以让led_ctrl产生一个时钟的高电平,在下一个时钟到来时用于控制led灯翻转。这种延时思路跟单片机是一样的,只是实现起来更复杂一些,同时也避免了用单片机做的时候的一个BUG,如果用单片机检测的话,万一在延时完毕判断按键值的时候按键抖动到了低电平,就有可能出现误判断误操作,但是FPGA则不会,因为按键每来一个下降沿计数器的值都会清0,一个抖动是不可能持续太长时间的低电平的,所以不会误触发。
7 ?# }! M: F; S2 l. f3 X下面上一个仿真的图用于说明具体的时序,很直观,但是我的程序里为了仿真方便,计数器的值为5,而且只仿真了其中一个按键,大家将就着凑合吧,欢迎拍砖。* J% q* B, P& N

0 U0 M/ D% w: ?  r. y4 N5 j: S
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-8-3 02:19 , Processed in 0.125000 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表