FPGA学习-Verilog实现独立按键消抖


前言

利用verilog语言实现独立按键消抖,文章首先对按键抖动产生的原因、消抖原理进行简要解释;之后详细阐述各模块verilog语言实现方法;最后利用四个独立按键控制led亮灭,在vivado下进行源码设计与仿真。(完成程序代码附在文章结尾)


一、独立按键消抖原理

按键一般是机械弹性开关,由于机械触点的弹性作用,机械触点断开、闭合时会伴随着一连串的抖动,这个抖动会使得按键输出的高低电平连续变化,而这并不是真正的按下按键,如果直接作为开关控制后续电路,就会造成电路的不稳定,因此,需要采用按键消抖。
机械按键按下时候有一个不稳定的抖动期,这个时间大概在20ms以内,我们可以利用这个20ms的抖动期,当检测到按键电平变化时20ms计数器重新计数,若计数器达到20ms,证明按键电平变化以后的20ms内没有再发生电平变化,可以认为是按键真正被按下,将此时的按键状态放入寄存器进而控制后续电路。

二、按键消抖程序实现(Verilog)

1.按键触发判断

  • 只要有按键状态变化,20ms计数器就应重新开始计数。而判断按键状态是否变化应该比较按键前后两个状态,由此采用移位寄存器,缓存按键前后的状态,再进行逻辑运算判断按键被按下还是松开。

注意:只要有按键被按下就要采用延时20ms消抖,同时按键全被松开也会对应按键电平的变化,仍然要采用消抖

代码如下:

wire key ; //用于按键触发判断
reg[3:0] key_r ; //缓存标志key的信息
assign key = key_h[3]&key_h[2]&key_h[1]&key_h[0] ;
always@(posedge sys_clk_i or negedge ext_rst_n)begin
	if(!ext_rst_n) key_r <= 4'b1111;
	else key_r <= {key_r[2:0],key}; //左移寄存器,最低位保存按键最新的状态
end

wire key_neg = key_r[3] & ~key_r[2] ; //key_r[2]是现态,[3]是前一个状态,采用左移寄存器
wire key_pos = ~key_r[3] & key_r[2] ;//按键全部被释放

2.计数器模块实现

  • 由于FPGA系统时钟是50MHz,需要计数到20ms 20ms/20ns得到结果为1_000_000次,表示需要每一个时钟上升沿计数,从0开始计数,计数到999_999,二十进制换算,需要采用20bit的寄存器来保存计数次数。
  • 计数至20ms时应进行清零操作
//20ms计数,一旦出现按键按下或释放重新开始计数
reg[19:0]cnt ;
always@(posedge sys_clk_i or negedge ext_rst_n)begin
	if(!ext_rst_n) cnt <= 20'd0 ;
	else if(key_neg || key_pos ) cnt <= 20'd0 ;
	else if(cnt == 20'd999_999) cnt <= 20'd0 ;
	else cnt <= cnt + 20'd1 ;
end

3.按键状态更新

模块输入的按键值【key_h】状态表示未消抖前按键的状态,而控制后续电路的应该是消抖后的按键状态,因此需要设置一个4bit的寄存器,用于保存消抖后的状态。
同时,由于我们时利用按键前后的状态比较来判断按键是否被按下,所以需要有两个4bit的寄存器,分别保存前后状态。

  • 【key_press】用于表示按键是否被按下
reg[3:0]key_value[1:0] ;
always@(posedge sys_clk_i or negedge ext_rst_n)begin
	if(!ext_rst_n)begin
		key_value[0] = 4'b1111; //保存最新的状态
		key_value[1] = 4'b1111;
	end
	else begin
		if(cnt == 20'd999_999) key_value[0] = key_h ;
		key_value[1] <= key_value[0];
	end
end
wire[3:0}key_press ;
assign key_press = key_value[1] & ~key_value[0] ;

4.按键控制led亮灭

//led状态控制模块
always@(posedge sys_clk_i or negedge ext_rst_n)begin
	if(!ext_rst_n) led <= 4'b1111 ;
	else begin
		if(key_press[0]) led[0] <= ~led[0];
		if(key_press[1]) led[1] <= ~led[1];
		if(key_press[2]) led[2] <= ~led[2];
		if(key_press[3]) led[3] <= ~led[3];
	end
end

三、仿真测试文件编写

`timescale 1ns / 1ps
module sim_keyboard(

    );
reg sys_clk_i ;
reg ext_rst_n ;
reg[3:0]key_h ;
wire[3:0]led ;
keyboard utt_keyboard(
	.sys_clk_i(sys_clk_i),
	.ext_rst_n(ext_rst_n),
	.key_h(key_h), //按键未按下时高电平,按下后低电平
	.led(led)
    );
initial begin
	sys_clk_i = 1'b0 ;
	ext_rst_n = 1'b0 ;
	key_h = 4'b1111 ;
	#1000
	@(posedge sys_clk_i) ; #2 ;
	ext_rst_n = 1'b1 ;
	@(posedge sys_clk_i) ; #2 ;

	//模拟按键抖动
	key_h[0] = 1'b0 ;
	#1000_000  ;//1ms
	key_h[0] = 1'b1 ;
	#5_000_000  ;//5ms
	key_h[0] = 1'b0 ;
	#3_000_000  ;//3ms
	key_h[0] = 1'b1 ;
	#1_000_000 
	key_h[0] = 1'b0 ;
	#1000_000  ;//1ms
	key_h[0] = 1'b1 ;
	#5_000_000  ;//5ms
	key_h[0] = 1'b0 ;
	#3_000_000  ;//3ms
	key_h[0] = 1'b1 ;
	#3_000_000  ;//3ms
	key_h[0] = 1'b0 ;
	#50_000_000  ;//50ms
	key_h[0] = 1'b1 ;
	#30_000_000  ;//30ms
	key_h[0] = 1'b0 ;
	#50_000_000  ;//50ms
	key_h[0] = 1'b1 ;
	$finish ;
end

always #10 sys_clk_i = ~sys_clk_i ;

endmodule

四、编译结果

  • 可以看到计数器计数到999_999,此时【key_h】的值为1110,【key_value[0]】值仍然为1111,在下一个时钟上升沿,消抖完成,【key_value[0]】会保存1110,表示按键key_h[0]被按下
    在这里插入图片描述
  • 下一个时钟上升沿计数器清零,重新开始20ms计数,key_value[0]即为消抖完成后案件的现态,key_value[1]表示按键的前一个状态,【key_press[0]】值为1,表示按键被按下。
    在这里插入图片描述
  • 测试文件模拟按键抖动过程,仿真结果可以看到当按键值【key_h】变化时,【key_pos】【key_neg】检测到边沿变化,但并不会引起【led】电平变化,说明消抖模块是有效的
    在这里插入图片描述
    代码
    链接:https://pan.baidu.com/s/1euNaVxH-goOatb3lxpe4aQ
    提取码:mcuh
Verilog按键消抖实现可以通过以下步骤进行: 1. 首先,了解按键抖动的原因和消抖的原理。按键抖动是指在按下或释放按键时,由于机械性质或电气性质的原因,导致按键信号出现多次变化的现象。消抖的原理是通过延时和状态判断来确定按键的有效状态。 2. 在Verilog中,可以使用状态机的方式来实现按键消抖。首先,定义一个状态机的状态,包括按键未按下、按键按下、按键释放等状态。然后,通过检测按键信号的变化来切换状态。 3. 在状态机的每个状态中,可以设置一个延时计数器来延时一段时间,以消除按键抖动。在延时结束后,再次检测按键信号的状态,如果仍然保持一致,则认为按键有效。 4. 根据具体需求,可以在按键有效时执行相应的操作,比如控制LED的亮灭。 综上所述,Verilog按键消抖实现可以通过状态机和延时计数器来实现,具体的代码实现可以参考引用\[1\]中提供的文章结尾的示例代码。 #### 引用[.reference_title] - *1* [FPGA学习-Verilog实现独立按键消抖](https://blog.csdn.net/qq_46490027/article/details/123338108)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Verilog按键消抖检测的实现](https://blog.csdn.net/CLL_caicai/article/details/105159165)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Verilog实现按键消抖](https://blog.csdn.net/m0_54218263/article/details/121328750)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值