FPGA初学-按键消抖

这篇博客介绍了FPGA新手如何处理按键输入时的抖动问题,通过新建工程并创建key_filter.v和key_filter_tb.v文件进行实战演练。
摘要由CSDN通过智能技术生成

新建工程,建立key_filter.v文件和key_filter_tb.v文件
在这里插入图片描述


			input Clk;
			input Rst_n;
			input key_in;
			
			output reg key_flag;
			output reg key_state;
			reg [19:0] cnt;
			reg en_cnt;//使能计数寄存器,在使能之后i,再开始计数			
			reg key_temp0,key_temp1;
			wire pedge,nedge;//pedge上升沿   nedge下降沿		
			reg cnt_full;//计数满寄存器,当计数满了之后,让cnt_full置1
			
			//定义状态值
			localparam
				IDLE     =4'b0001,//空闲状态
				FILTER0  =4'B0010,//按键抖动期
				DOWN     =4'B0100,//按下稳定期
				FILTER1  =4'B1000;
				
				
			reg [3:0]state;//状态
			
			//边沿检测,检测下降沿。如果想知道它是否有下降沿,我们可以判断,如果前一个时刻是高电平,下一个时刻是低电平,那么一定会有一个下降沿
			//所以对前一时刻和后一时刻的状态寄存,再通过组合逻辑进行比较,来判断是否有下降沿
			//通过时钟对信号进行采样
			//按键输入key_in到reg0,reg0的输出连接到reg1的输入,两个reg是同一个时钟
			//当key_in第一次输入为高电平,那么就保存到reg0.下一个时钟上升沿到来时,reg0里面的数值传输到reg1,同时当key_in第二次为低电平,则reg0又记录key_in的新的状态
			//通过比较两个寄存器的输出,就可以进行比较
			//将reg0和reg1第三次时钟的时候的输出的信息,将reg0通过取反之后,再将两者通过与门
			
			
//			reg key_temp0,key_temp1;
//			wire pedge,nedge;//pedge上升沿   nedge下降沿
			always@(posedge Clk or negedge Rst_n)begin
				if(!Rst_n)begin
					key_temp0=1'b0;
					key_temp1=1'b0;//当复位的时候,给两个数值清零
				end 
				else begin 
					key_temp0<=key_in;
					key_temp1<=key_temp0;//否则,当时钟上升沿到来时,key_temp0记录这个时候的key_in的值,同时把key_temp0里面的值传给key_temp1.注意这是非阻塞赋值,二者是同时进行的,也就是说,key_temp1里面保存的是上一个时钟上升沿中,key_temp0所保存的值。
					
				end 
				end
				assign nedge = !key_temp0 & key_temp1;
				assign pedge = key_temp0 & (!key_temp1);//!取反    ~按位取反   因为这里temp是一位的,所以! 和  ~是一样的
				//0110   ~    1001
				//0110   !   0000
				
			
				
				//接下来编写状态机
				
				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//处于空闲状态的时候,如果检测到了下降沿,就进入下一个抖动状态
									//此时还需要使能我们的计数器en_cnt
										state<=FILTER0;
										en_cnt<=1'b1;
										
									end
									else 
										state<=IDLE;
								end
							FILTER0:
								if(cnt_full)begin //当计数器满的时候,也就是说计数到了
									key_flag<=1'b1;//那么它确实是一个下降沿,那么久给flag置一,同时给key_state置零
									key_state<=1'b0;
									state<=DOWN;
									en_cnt<=1'b0;
								end
								else if(pedge)begin
									state<=IDLE;//否则,当我们检测到上升沿的时候,说明这只是一次抖动,我们回到idle状态,等待下一个时钟下降沿的到来
									en_cnt<=1'b0;
								end
								else//没有计满,也没有检测到上升沿
									state<=FILTER0;
									
							DOWN:
								begin 
									key_flag<=1'b0;
									if(pedge)begin//这个时候检测到上升沿了,按键可能开始释放了,那么就让state进入滤波状态
											state<=FILTER1;
											en_cnt<=1'b1;//让计数器开始计数
									end
									else
										state<=DOWN;
								end
							FILTER1:
								if(cnt_full)begin
									state<=IDLE;
									key_flag<=1'b1;
									key_state<=1'b1;								
								end
								else if(nedge)begin //如果计数还没有满,说明这只是一次抖动
									en_cnt<=1'b0;
									state<=DOWN;

								end
								else
									state<=FILTER1;
							default:begin 
								state<=IDLE;
								en_cnt<=1'b0;
								key_flag<=1'b0;
								key_state<=1'b1;
							end
						endcase

			end
		
		//系统时钟是50 000 000,20ns
		//我们延时20ms,20——000——000ns
		//我们需要计数1 000 000次
		
		//当在idle状态中检测到下降沿的时候,我们开始计数
		//在filter0状态中,如果我们检测到了上升沿或者计数还没有计满的时候
		
			
//		reg [19:0] cnt;
//		reg en_cnt;//使能计数寄存器,在使能之后i,再开始计数
		always@(posedge Clk or negedge Rst_n)
				if(!Rst_n)
					cnt<=20'd0;
				else if(en_cnt)
					cnt<=cnt+1'b1;
				else 
					cnt<=20'd0;
					
//				reg cnt_full;//计数满寄存器,当计数满了之后,让cnt_full置1

		always@(posedge Clk or negedge Rst_n)
				if(!Rst_n)
					cnt_full<=1'b0;
				else if(cnt==999_999)
					cnt_full<=1'b1;
				else 
					cnt_full<=1'b0;
					
				



endmodule 
`timescale 1ns/1ns
`define clock_period 20

module key_filter_tb;

	reg Clk;
	reg Rst_n;
	reg key_in;
	
	wire key_flag;
	wire key_state;


	key_filter key_filter0
	(
		.Clk
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值