Verilog中的按键消抖

Verilog 按键消抖模块

遇到的问题:第一边沿检测以及对key_flag和key_state的作用了解耗费了我很多时间,经过不断的分析后还是找出了错误
		  在解决问题的过程中让我也对层次化设计FPGA更加了解,同时对阻塞赋值和非阻塞赋值也有了更深刻的了解,熟悉了
		  定时器的设计与应用

感悟:FPGA是个大坑啊,进去了就出不来了,哈哈哈!		
	希望自己在接下来的路上越搓越勇
设计代码:
/*
 *NAME: Rayone
 *DATE: 2019/5/21
 *FUNC: key filter
 */
module key_filter(Clk,Rst_n,key_in,key_flag,key_state);
//端口定义
	input Clk;
	input Rst_n;
	input key_in;
	
	output reg key_flag; //滤波后如果检测确实按下了将其置1
	output reg key_state;//按键在空闲稳定状态下为1 在按下稳定状态为0

//key_filter模块设计
//——>利用两级D触发器降低亚稳态发生的可能
	reg key_in_tmpa,key_in_tmpb;
	always@(posedge Clk or negedge Rst_n)
		if(!Rst_n)begin
			key_in_tmpa <= 1'b0;
			key_in_tmpb <= 1'b0;
		end
		else begin
			key_in_tmpa <= key_in;
			key_in_tmpb <= key_in_tmpa;
		end
		
//——>捕获key_in变化信号
	wire pedge,nedge;//key_in的上升沿和下降沿
	reg key_in_a,key_in_b;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_in_a <= 1'b0;
		key_in_b <= 1'b0;
	end
	else begin
		key_in_a <= key_in_tmpb;//key_in_tmpb是key_in经过二级D触发器处理后的,这里是非阻塞赋值
										//key_in_a在给key_in_b赋值的同时也给key_in_b赋值,处于时时更新的
		key_in_b <= key_in_a;
	end
	//now :key_in_a   ago :key_in_b
	assign pedge = ((!key_in_b) & key_in_a);	//key_in上升沿信号到来
	assign nedge = ( key_in_b & (!key_in_a));//key_in下降沿信号到来
	
	
	//前期设计已经准备好了,接下来就是状态机的设计
	localparam  //one-hot code
		IDLE 	  = 4'b0001,
		FILTER0 = 4'b0010,
		DOWN 	  = 4'b0100,
		FILTER1 = 4'b1000;

	//用一个状态寄存器保存状态
		reg [3:0]state;
		
	//设计定时器
	reg [19:0]cnt;		//——>需要一个计数寄存器,因为只用计数20ms,所以一个20位的寄存器已经足够了
	reg en_cnt;   		//——>计数器开始计数使能信号
	reg cnt_full_flag;//——>计数器加满标志
	
	//状态机设计
	always@(posedge Clk or negedge Rst_n)
		if(!Rst_n)begin
			state <= IDLE;
			en_cnt <= 1'b0;
			key_flag <= 1'b0;
			key_state <= 1'b1;
		end
		else begin 
			case(state)
				IDLE:begin
					key_flag <= 1'b0;
					if(nedge)begin//如果检测到下降沿
						state <= FILTER0;//进入按下抖动滤波状态
						en_cnt <= 1'b1;  //使能计数(此时需要计时20ms,前面我们没有设计计数器,于是我们在最后设计一个计数器哦)
					end
					else 
						state <= IDLE;
				end	
				
				FILTER0:begin
					if(cnt_full_flag)begin
						state <= DOWN;
						en_cnt <= 1'b0;
						key_flag <= 1'b1;	//标志按键此时确实按下
						key_state <= 1'b0;//此时按键处于按下稳定状态
					end
						else if(pedge)begin
							en_cnt <= 1'b0;
							state <= IDLE;	
						end
					else 
						state <= FILTER0;	
				end
				
				DOWN:begin
					key_flag <= 1'b0;
					if(pedge)begin
						en_cnt <= 1'b1;
						state <= FILTER1;
					end	
					else
						state <= DOWN;
				end
				
				FILTER1:begin
					if(cnt_full_flag == 1'b1)begin
						state <= IDLE;		//计数满标志成功计数
						en_cnt <= 1'b0;	//关闭计数
//						key_flag <= 1'b1;	//标志按键此时确实释放
						key_state <= 1'b1;//空闲稳定状态下为1
					end
					else if(nedge)begin
							en_cnt <= 1'b0;
							state <= DOWN;	
					end
					else 
						state <= FILTER1;	
				end
				default:
					begin 
						state <= IDLE; 
						en_cnt <= 1'b0;		
						key_flag <= 1'b0;
						key_state <= 1'b1;
					end
					
			endcase
	end
		

//计数器加1操作	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		cnt <= 20'd0;
	end
	else if(en_cnt)
		cnt <= cnt + 1'b1;
	else 
		cnt <= 20'd0;

//产生计数20ms满信号 cnt_full_flag	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt_full_flag <= 1'b0;
	else if(cnt == 999_999)
		cnt_full_flag <= 1'b1;
	else 
		cnt_full_flag <= 1'b0;
		
endmodule

按键的状态图:
按键状态转换图

仿真波形图:
在这里插入图片描述

可以看到:当检测到按键按下时key_flag置1表示按键已经按下,key_state用于判断按下后是否处于稳定状态,如果要将该模块运用于其他模块就可以通过检测这两个信号状态来进行使用
module led_ctrl(Clk,Rst_n,key_flag0,key_flag1,key_state0,key_state1,led);

	input Clk;
	input Rst_n;
	input key_flag0,key_flag1;
	
	input key_state0,key_state1;
	
	output [3:0]led;
	
	reg [3:0]led_r;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		led_r <= 4'b0000;
	else if(key_flag0 && !key_state0)
		led_r <= led_r + 1'b1;
	else if(key_flag1 && !key_state1)
		led_r <= led_r - 1'b1;
	else
		led_r <= led_r;
		
	assign led = ~led_r;
		
endmodule

这里就是通过检测key_flag(按键是否按下)和key_state(是否处于稳定状态)来使4个led表示的二进制数的加1和减1操作
  • 10
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Verilog实现按键消抖的方法是通过添加适当的延迟和边沿检测技术来实现的。 首先,按键消抖的基本原理是通过适当的延迟来判断按键是否被按下或释放。这个延迟可以使得按键抖动部分不会被检测到,从而滤除掉抖动的影响,实现按键消抖。延迟时间通常很短,例如10毫秒,这样可以避免漏检真实按下或释放按键的情况。 其次,按键消抖的关键技术之一是边沿检测。边沿检测是通过检测延迟前后按键输出电平值的变化来判断按键是否发生了边沿信号。边沿检测可以分为上升沿检测和下降沿检测。当按键从低电平变为高电平时,称为上升沿;当按键从高电平变为低电平时,称为下降沿。通过检测这些边沿信号,可以确定按键的按下和释放动作。 因此,在Verilog实现按键消抖的关键步骤包括: 1. 添加合适的延迟,通常为几毫秒的时间。这可以通过使用计数器或者延时模块来实现。 2. 在延迟前后对按键的输出电平进行检测,判断边沿信号的变化。 3. 根据边沿信号的变化来确定按键的按下和释放动作,进而实现按键消抖。 综上所述,Verilog实现按键消抖的方法包括添加适当的延迟和使用边沿检测技术来判断按键的按下和释放动作。这样可以有效地滤除按键抖动,保证按键信号的稳定性和可靠性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值