关于按键消抖实验的疑问
时间:10-02
整理:3721RD
点击:
//说明:按键消抖实验
//当三个独立按键的某一位被按下后,相应的Led被点亮;
//再次按下后,LED熄灭,按键控制LED亮灭;//
//
module key_handle(
clk_20M,rst_n,
sw1_n,sw2_n,sw3_n,
led_d1,led_d2,led_d3
);
input clk_20M; //主时钟信号,20MHz
input rst_n;//复位信号,低电平有效
input sw1_n,sw2_n,sw3_n;// 三个独立按键,低表示被按下
output led_d1,led_d2,led_d3;//发光二极管,分别由按键控制
//------------------------NOTE:两个寄存器不要放在一个always语句里面---------------------------------------
reg[2:0] key_rst; //对后面20ms计数器的一个复位的操作
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) key_rst <= 3'b111;
else key_rst <= {sw3_n,sw2_n,sw1_n};
reg[2:0] key_rst_r; //每个时钟周期的上升沿将上次锁存的按键值key_rst锁存到key_rst_r中
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) key_rst_r <= 3'b111;
else key_rst_r <= key_rst;
//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期
wire [2:0] key_an;
assign key_an = key_rst_r & (~key_rst); //边沿检测技术
/*下面表示的一个按键的状态
key_rst 1 1 1 0 0 1 //按键从1变为0
~key_rst 0 0 0 1 1 0
key_rst_r 1 1 1 0 0 1
key_an 0 0 1 0 0 //key_an会变为1,且高电平保持一个时钟周期
*/
//-------------------------------------------------------
reg [19:0] cnt;//cnt用来计数20ms 2^20~=20ms;按键按下的时间差不多为20ms
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) cnt <= 20'd0;
else if(key_an) cnt <= 20'd0;//如果检测到有键按下,那么就将计数器清0,从新开始计数
else cnt <= cnt + 1'b1;
reg[2:0] low_sw;
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) low_sw <= 3'b111;
else if (cnt == 20'hfffff) // 每20ms将按键值锁存到寄存器low_sw中
low_sw <= {sw3_n,sw2_n,sw1_n}; //这里存的值是稳定的(下一个脉冲的某一个时刻)
//这个值是滤除抖动后的稳定值
//-----------------------------------------------------------
reg [2:0] low_sw_r;
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) low_sw_r <= 3'b111;
else low_sw_r <= low_sw; //每一个时钟采集一次low_sw的状态值
//每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
/*low_sw 111 111 111 110 110 110
~low_sw 000 000 000 001 001 001
low_sw_r 111 111 111 110 110 110
led_sw_r 000 000 001 000 000
*/
// 当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
wire[2:0] led_ctrl = low_sw_r[2:0] & (~low_sw[2:0]);
// --------------------------------------------------------
reg d1;
reg d2;
reg d3;
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) begin
d1 <= 1'b0;
d2 <= 1'b0;
d3 <= 1'b0;
end
else begin ////某个按键值变化时,LED将做亮灭翻转
if(led_ctrl[0]) d1<=~d1;
if(led_ctrl[1]) d2<=~d2;
if(led_ctrl[2]) d3<=~d3;
end
assign led_d3 = d1 ? 1'b1:1'b0; //LED翻转输出
assign led_d2 = d2 ? 1'b1:1'b0;
assign led_d1 = d3 ? 1'b1:1'b0;
endmodule
这是特权同学的程序代码,基本上我都能搞清楚是什么意思,low_sw是存放按键稳定后的按键值;心里老感觉模模糊糊的;就我自己理解的,首先用key_an来标志是否有键按下。有键按下,cnt计数器清零,这个键不管是正常按下还是抖动,计数20ms以后都应该是稳定的值low_sw;我不理解的地方就是第二个边沿检测是用来做什么的;按键消抖从软件上实现应该就是检测到按键按下后,一段时间20ms后再检测应该是稳定的;也就实现了这个功能,大家觉得我理解的对不对?
//当三个独立按键的某一位被按下后,相应的Led被点亮;
//再次按下后,LED熄灭,按键控制LED亮灭;//
//
module key_handle(
clk_20M,rst_n,
sw1_n,sw2_n,sw3_n,
led_d1,led_d2,led_d3
);
input clk_20M; //主时钟信号,20MHz
input rst_n;//复位信号,低电平有效
input sw1_n,sw2_n,sw3_n;// 三个独立按键,低表示被按下
output led_d1,led_d2,led_d3;//发光二极管,分别由按键控制
//------------------------NOTE:两个寄存器不要放在一个always语句里面---------------------------------------
reg[2:0] key_rst; //对后面20ms计数器的一个复位的操作
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) key_rst <= 3'b111;
else key_rst <= {sw3_n,sw2_n,sw1_n};
reg[2:0] key_rst_r; //每个时钟周期的上升沿将上次锁存的按键值key_rst锁存到key_rst_r中
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) key_rst_r <= 3'b111;
else key_rst_r <= key_rst;
//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期
wire [2:0] key_an;
assign key_an = key_rst_r & (~key_rst); //边沿检测技术
/*下面表示的一个按键的状态
key_rst 1 1 1 0 0 1 //按键从1变为0
~key_rst 0 0 0 1 1 0
key_rst_r 1 1 1 0 0 1
key_an 0 0 1 0 0 //key_an会变为1,且高电平保持一个时钟周期
*/
//-------------------------------------------------------
reg [19:0] cnt;//cnt用来计数20ms 2^20~=20ms;按键按下的时间差不多为20ms
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) cnt <= 20'd0;
else if(key_an) cnt <= 20'd0;//如果检测到有键按下,那么就将计数器清0,从新开始计数
else cnt <= cnt + 1'b1;
reg[2:0] low_sw;
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) low_sw <= 3'b111;
else if (cnt == 20'hfffff) // 每20ms将按键值锁存到寄存器low_sw中
low_sw <= {sw3_n,sw2_n,sw1_n}; //这里存的值是稳定的(下一个脉冲的某一个时刻)
//这个值是滤除抖动后的稳定值
//-----------------------------------------------------------
reg [2:0] low_sw_r;
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) low_sw_r <= 3'b111;
else low_sw_r <= low_sw; //每一个时钟采集一次low_sw的状态值
//每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
/*low_sw 111 111 111 110 110 110
~low_sw 000 000 000 001 001 001
low_sw_r 111 111 111 110 110 110
led_sw_r 000 000 001 000 000
*/
// 当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
wire[2:0] led_ctrl = low_sw_r[2:0] & (~low_sw[2:0]);
// --------------------------------------------------------
reg d1;
reg d2;
reg d3;
always @(posedge clk_20M or negedge rst_n)
if(!rst_n) begin
d1 <= 1'b0;
d2 <= 1'b0;
d3 <= 1'b0;
end
else begin ////某个按键值变化时,LED将做亮灭翻转
if(led_ctrl[0]) d1<=~d1;
if(led_ctrl[1]) d2<=~d2;
if(led_ctrl[2]) d3<=~d3;
end
assign led_d3 = d1 ? 1'b1:1'b0; //LED翻转输出
assign led_d2 = d2 ? 1'b1:1'b0;
assign led_d1 = d3 ? 1'b1:1'b0;
endmodule
这是特权同学的程序代码,基本上我都能搞清楚是什么意思,low_sw是存放按键稳定后的按键值;心里老感觉模模糊糊的;就我自己理解的,首先用key_an来标志是否有键按下。有键按下,cnt计数器清零,这个键不管是正常按下还是抖动,计数20ms以后都应该是稳定的值low_sw;我不理解的地方就是第二个边沿检测是用来做什么的;按键消抖从软件上实现应该就是检测到按键按下后,一段时间20ms后再检测应该是稳定的;也就实现了这个功能,大家觉得我理解的对不对?
是的,可以这样理解~
可以解释一下第二个脉冲边沿检测是干嘛的不
可以解释一下第二个脉冲边沿检测是干嘛的不
最讨厌看那些没有一点注释的程序。
我这个勉强过得去吧
韦东山貌似是搞Arm-Linux的...
来确认按下之后是稳定的状态啊
你觉得如果是理想的按键(也就是完全没有抖动),你要不要做边沿检测?要吧,第二个边沿检测就是用来干这个的。
第一个应该是分频,第二个是双寄存器防亚稳态