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

特权的按键消抖的理解

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
特权的按键消抖的理解
昨天上午看的视频,特权的按键消抖,想了好久,到现在终于弄明白了,下面是我理解的方式:
; B/ e& R. e* |+ [6 l2 f先上他的程序:
( @" d' j+ w+ A1 R
9 e# f# @3 w, s8 Q/ J; X) _2 Xmodule key_led(clk,rst_n,sw1_n,sw2_n,sw3_n,; ]* I& ]7 D2 o6 G5 [9 f
      led_d3,led_d4,led_d5,
4 J3 H8 x" r; v4 R4 w   Q1,Q2,Q3,Q4,Q5,Q66 F, v  }  u/ J# u
);
& d/ h7 A; U/ p& J/ Z' b% Dinput   clk; //主时钟信号,50MHz" F( j( x/ l3 Q# p" P
input   rst_n; //复位信号,低有效6 a; u$ K2 ~/ `
input   sw1_n,sw2_n,sw3_n;  //三个独立按键,低表示按下
) `! a( S( F( U( H/ j- S& {. F0 g" @. Houtput  led_d3,led_d4,led_d5; //发光二极管,分别由按键控制8 e/ y% V& _" g% R, o9 Y
output  Q1,Q2,Q3,Q4,Q5,Q6;
5 x' o* A1 |; |6 C( rreg[2:0] key_rst; - r1 M0 s# M$ x8 _( Y; K" u
always @(posedge clk  or negedge rst_n)   9 A/ S" {; O4 Q/ m: O
if (!rst_n) key_rst <= 3'b111;  ( O5 c% p" G" M( |; D+ B1 @/ D
else key_rst <= {sw3_n,sw2_n,sw1_n};
- o: X4 \& V3 Nreg[2:0] key_rst_r;       //每个时钟周期的上升沿将key_rst信号锁存到key_rst_r5 H' x( L+ ?' j

$ p( S8 y! R1 j/ oalways @ ( posedge clk  or negedge rst_n )   
3 }  o4 P: r! M. ?' [4 R if (!rst_n) key_rst_r <= 3'b111;  
: s, o" C% Z/ v* f/ ?8 V$ x else key_rst_r <= key_rst;  
# e: o/ W( r  s; T; j5 v$ ?) e& }//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期6 i9 P7 r7 e2 b& {# g8 q
wire[2:0] key_an = key_rst_r & ( ~key_rst);
5 L6 h0 f6 g/ P5 D) q8 ireg[2:0]  cnt; //计数寄存器7 ~9 m5 _$ _% k' A4 h
always @ (posedge clk  or negedge rst_n)  
! q8 a8 K, J9 `8 g if (!rst_n) cnt <= 3'd0; //异步复位 : ?4 v( h1 S, x) L5 U) \, z3 b
else if(key_an) cnt <=3'd0;  " f; D) b% Z" y
else cnt <= cnt + 1'b1;5 Z4 a" D" l3 S# e: m
reg[2:0] low_sw;& W' s9 M( V2 y) `: h* E/ x" Q, t* X
always @(posedge clk  or negedge rst_n)   
% D3 W- }1 \- h6 D* r% k1 W+ Wif (!rst_n) low_sw <= 3'b111;    1 P/ O9 k0 {( t# L  Z, s
else if (cnt == 3'd5)  //满60ns,将按键值锁存到寄存器low_sw中      
, T1 [( T  K' Z2 O; Fbegin ( y; |# [" L6 x" j1 O
low_sw <= {sw3_n,sw2_n,sw1_n};0 R- ^) B! k7 q. r- G
end
" C( A  a  O. z! ]0 Wreg  [2:0] low_sw_r;       //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中; c, C0 P$ b! k* s' ~1 g- L9 m0 B
always @ ( posedge clk  or negedge rst_n )2 n4 w2 H) B$ a; @
if (!rst_n) low_sw_r <= 3'b111; . f7 ~& v: X# z3 x# n2 y+ I
else low_sw_r <= low_sw;; U, d! u7 ^. h; l  k9 B) ^
   
' d- K8 W( f+ d' F% @//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期5 A; G; b, c7 [! e$ ]5 _* p
' c7 P0 Y. i0 _2 E  B
wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);, a. V1 r" O/ m0 K" f: V/ i$ @2 G4 Z
reg d1;3 ?( z7 a! k$ W1 V* R, M: E: y! w8 {
reg d2;& W9 u& T) S+ `2 c  N% k
reg d3;
  B" [) r  m( {7 ralways @ (posedge clk or negedge rst_n)  ; q  q% G" V5 M; n
if (!rst_n) begin- ?1 z4 {0 @7 c" V# z5 G
        d1 <= 1'b0;; H; l7 b" _& w7 l# v% U
        d2 <= 1'b0;
0 P# c* q  m5 A& d3 U        d3 <= 1'b0;7 O; z* ~- I. f- o' |6 k1 C3 _
      end   + e6 Y. L" A0 w9 q6 X& J
else begin  //某个按键值变化时,LED将做亮灭翻转      
" a1 |3 Y) F7 i% O if ( led_ctrl[0] ) d1 <= ~d1;
, s$ J2 y$ d6 q9 a& o        if ( led_ctrl[1] ) d2 <= ~d2;% x( Z- I% T; P  L" P4 k; O6 y
        if ( led_ctrl[2] ) d3 <= ~d3;; ]! R4 C' a" R
      end
; F$ |0 K* {7 y' u+ Aassign led_d3 = d1 ? 1'b1 : 1'b0;  //LED翻转输出
& o$ f4 L& N* L3 P: N6 Qassign led_d4 = d2 ? 1'b1 : 1'b0;6 R7 k+ G; s; ^% q  H
assign led_d5 = d3 ? 1'b1 : 1'b0;
+ G) H, J0 P& h; c* x$ qassign Q1=key_rst;
1 s4 v. A! G& e6 xassign Q2=key_rst_r;
0 A5 h: i8 ?9 v$ A7 W) w) B6 iassign Q3=key_an;7 T+ G4 n$ [/ `: |! Z
assign Q4=low_sw;2 h6 t" \* c4 f, u
assign Q5=low_sw_r;+ K3 m- e# r3 b, k$ B
assign Q6=led_ctrl;* V( {7 ^8 T2 v; |
endmodule8 C# K& K0 ?6 J" z
4 x5 R& I% w( V! N. p
个人刚开始看这个程序,只是觉得FPGA太复杂了,一个按键消抖而已,,程序写的好复杂,寄存器也用掉了不少,不过这也是没办法的 事,入正题,* U9 V$ x1 z. F5 G+ e
他的思路其实就是按键那边每来一个下降沿,有一个寄存器的值key_an就会保持一个时钟脉冲的高电平,并且这个高电平用于给延时计数器的计数清零,这种方法的好处就在于毛刺全部消失后,就是按键按下去稳定后计数器才开始计数,比较可靠,之后计数器计数到设定好时间后,判断此时的按键是否按下,若按键值为0(按键一直保持按下状态,没有抖动),则把按键值存入一个寄存器low_sw,这个寄存器之前是一直保持为1的,所以这个时候也会有一个下降沿发生,同样的道理可以让led_ctrl产生一个时钟的高电平,在下一个时钟到来时用于控制led灯翻转。这种延时思路跟单片机是一样的,只是实现起来更复杂一些,同时也避免了用单片机做的时候的一个BUG,如果用单片机检测的话,万一在延时完毕判断按键值的时候按键抖动到了低电平,就有可能出现误判断误操作,但是FPGA则不会,因为按键每来一个下降沿计数器的值都会清0,一个抖动是不可能持续太长时间的低电平的,所以不会误触发。
% C% X4 Z9 u& ?下面上一个仿真的图用于说明具体的时序,很直观,但是我的程序里为了仿真方便,计数器的值为5,而且只仿真了其中一个按键,大家将就着凑合吧,欢迎拍砖。
: R5 N/ _  W" E

% N" F/ A6 s) }/ X) D# A4 ^2 S8 ~3 n
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-10-9 20:03 , Processed in 0.125000 second(s), 23 queries , Gzip On.

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

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

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