其他分享
首页 > 其他分享> > 按键消抖实验

按键消抖实验

作者:互联网

当按键被按下在到被释放,期间产生的输入信号会发生抖动,如果不进行消抖处理,直接使用可能就会误触发。

按键消抖实验设计思路,当按键被按下,隔20ms取数据,也就是说20ms的前后各取一次数据进行边沿检测:

(1)、需要一个计数器cnt,因为按键随时都可能会被按下,所以计数器需一直启动在计数,需一直在检测。

 1 always @(posedge clk or negedge rst_n)begin
 2     if(!rst_n)begin
 3         cnt <= 0;
 4     end
 5     else if(add_cnt)begin
 6         if(end_cnt)begin
 7             cnt <= 0;
 8         end
 9         else begin
10             cnt <= cnt + 1;
11         end
12     end
13 end
14 
15 assign add_cnt = 1;
16 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en;

(2)、需要一个边沿检测器,需要对输入pin 上的信号进行边沿检测,检测到下降沿之后,立刻马上将计数器cnt 清0 ,cnt从0开始计数,数到20ms 取一次数据

 1 always @(posedge clk or negedge rst_n)begin
 2     if(!rst_n)begin
 3         key_rst <= 1;
 4         key_rst_r <= 1;
 5     end
 6     else begin
 7         key_rst <= wr_en;
 8         key_rst_r <= key_rst;
 9     end
10 end
11 //当key_en = 1时,说明有检测到下降沿,但这个并不能当做一个真正有效的信号去启动cnt0,
12 //在按键按下到释放期间可能会多次产生key_en = 1
13 assign key_en = key_rst_r & (~key_rst); 
 1 //每隔20ms就取按键上的值    
 2 always @(posedge clk or negedge rst_n)begin
 3     if(!rst_n) begin
 4         pin_status <= 1;
 5     end
 6     else if(end_cnt) begin //隔20ms 取一次数据
 7         pin_status <= wr_en;
 8     end
 9 end
10 
11 always @(posedge clk or negedge rst_n)begin
12     if(!rst_n)begin 
13         pin_status_r <= 1;
14     end
15     else begin
16         pin_status_r <= pin_status;
17     end
18 end
19 
20 //前20MS的值与后20MS的值
21 assign pin_status_ctrl = pin_status_r & (~pin_status);//这个信号才比较稳定信号,可以当做启动计数器cnt0

完整代码:该代码是基于spi flash 一个读ID操作

  1 module spi_flash(
  2                     clk,
  3                     rst_n,
  4                     wr_en,
  5                     spi_miso,
  6                     
  7                     spi_sclk,
  8                     spi_mosi,
  9                     spi_cs,
 10                     rec_buf
 11 );
 12 parameter         SCLK_CLK = 3'd04;
 13 parameter         T_20MS      = 20'd1_000_000;
 14 parameter        CMD_ID     = 8'h9f;
 15 
 16 input            clk        ;
 17 input            rst_n    ;
 18 input            wr_en    ;
 19 input            spi_miso;
 20 
 21 output            spi_sclk;
 22 output            spi_mosi;
 23 output            spi_cs    ;
 24 output[24-1:0]    rec_buf    ;
 25 
 26 wire             add_cnt0;
 27 wire            end_cnt0;
 28 wire             add_cnt1;
 29 wire            end_cnt1;
 30 wire             add_cnt/*synthesis keep=1*/;
 31 wire            end_cnt/*synthesis keep=1*/;
 32 wire             key_en/*synthesis keep=1*/;
 33 
 34 wire            key_h_2_l;
 35 wire              pin_status_ctrl/*synthesis keep=1*/;
 36 
 37 reg[3-1:0]        cnt0;
 38 reg[6-1:0]        cnt1;
 39 reg[20-1:0]     cnt/*synthesis preserve=1*/;
 40 reg             wr_vld;
 41 reg             key_rst;
 42 reg             key_rst_r;
 43 reg             pin_status;
 44 reg             pin_status_r;
 45 
 46 
 47 /************************************************/
 48 //按键消抖动
 49 always @(posedge clk or negedge rst_n)begin
 50     if(!rst_n)begin
 51         key_rst <= 1;
 52         key_rst_r <= 1;
 53     end
 54     else begin
 55         key_rst <= wr_en;
 56         key_rst_r <= key_rst;
 57     end
 58 end
 59 
 60 assign key_en = key_rst_r & (~key_rst);
 61 
 62 //每隔20ms就取按键上的值    
 63 always @(posedge clk or negedge rst_n)begin
 64     if(!rst_n) begin
 65         pin_status <= 1;
 66     end
 67     else if(end_cnt) begin
 68         pin_status <= wr_en;
 69     end
 70 end
 71 
 72 always @(posedge clk or negedge rst_n)begin
 73     if(!rst_n)begin 
 74         pin_status_r <= 1;
 75     end
 76     else begin
 77         pin_status_r <= pin_status;
 78     end
 79 end
 80 
 81 //前20MS的值与后20MS的值
 82 assign pin_status_ctrl = pin_status_r & (~pin_status);
 83 
 84 always @(posedge clk or negedge rst_n)begin
 85     if(!rst_n)begin
 86         cnt <= 0;
 87     end
 88     else if(add_cnt)begin
 89         if(end_cnt)begin
 90             cnt <= 0;
 91         end
 92         else begin
 93             cnt <= cnt + 1;
 94         end
 95     end
 96 end
 97 
 98 assign add_cnt = 1;
 99 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en;
100 
101 
102 always @(posedge clk or negedge rst_n)begin
103     if(!rst_n)begin
104         wr_vld <= 0;
105     end
106     else if(pin_status_ctrl)begin
107         wr_vld <= 1;
108     end
109     else if(end_cnt1)begin
110         wr_vld <= 0;
111     end
112 end
113 
114 always @(posedge clk or negedge rst_n)begin
115     if(!rst_n)begin
116         cnt0 <= 0;
117     end
118     else if(add_cnt0)begin
119         if(end_cnt0)begin
120             cnt0 <= 0;
121         end
122         else begin
123             cnt0 <= cnt0 + 1;
124         end
125     end
126 end
127 
128 assign add_cnt0 = wr_vld;
129 assign end_cnt0 = add_cnt0 && cnt0 == SCLK_CLK -1;
130 
131 always @(posedge clk or negedge rst_n)begin
132     if(!rst_n)begin
133         cnt1 <= 0;
134     end
135     else if(add_cnt1)begin
136         if(end_cnt1)begin
137             cnt1 <= 0;
138         end
139         else begin
140             cnt1 <= cnt1 + 1;
141         end
142     end
143 end
144 
145 assign add_cnt1 = end_cnt0;
146 assign end_cnt1 = add_cnt1 && cnt1 == 33 -1;
147 
148 reg spi_sclk;
149 always @(posedge clk or negedge rst_n)begin
150     if(!rst_n)begin
151         spi_sclk <= 1;
152     end
153     else if(end_cnt0 && cnt1 != 32)begin
154         spi_sclk <= 0;
155     end
156     else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1))begin
157         spi_sclk <= 1;
158     end
159 end
160 
161 reg spi_cs;
162 always @(posedge clk or negedge rst_n)begin
163     if(!rst_n)begin
164         spi_cs <= 1;
165     end
166     else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1) && cnt1 == 0)begin
167         spi_cs <= 0;
168     end
169     else if(end_cnt1)begin
170         spi_cs <= 1;
171     end
172 end
173 
174 reg spi_mosi;
175 always @(posedge clk or negedge rst_n)begin
176     if(!rst_n)begin
177         spi_mosi <= 1;
178     end
179     else if(end_cnt0 && cnt1 >= 0 && cnt1 < 8)begin
180         spi_mosi <= CMD_ID[7-cnt1];
181     end
182 end
183 
184 reg[24-1:0] rec_buf_temp;
185 always @(posedge clk or negedge rst_n)begin
186     if(!rst_n)begin
187         rec_buf_temp <= 0;
188     end
189     else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1)-1) && cnt1 >= 9 && cnt1 < 33)begin
190         rec_buf_temp[32-cnt1] <= spi_miso;
191     end
192 end
193 
194 reg dout_vld;
195 always @(posedge clk or negedge rst_n)begin
196     if(!rst_n)begin
197         dout_vld <= 0;
198     end
199     else begin
200         dout_vld <= end_cnt1;
201     end
202 end
203 
204 reg[24-1:0] rec_buf;
205 always @(posedge clk or negedge rst_n)begin
206     if(!rst_n)begin
207         rec_buf <= 0;
208     end
209     else if(end_cnt1)begin
210         rec_buf <= rec_buf_temp;
211     end
212 end
213 
214 endmodule 
View Code

用quartus II 的SignalTab抓取的波形:

 

如果pin_status_ctl 检测到多次,可以将间隔时间适当的加长点。一般的轻触按键20~50ms。

触发条件可以多开几个窗口进行捕获观察 。

 

标签:begin,wire,消抖,spi,实验,cnt1,按键,rst,reg
来源: https://www.cnblogs.com/wen2376/p/16171571.html