【FPGA——Cyclone Ⅳ学习笔记】三.按键消抖(EP4CE6F17C8)

一.需要按键消抖原因

由于按键的弹性作用,在按下按键或释放按键时,按键会有抖动(在高低电平之间任意变化),而不是立刻稳定。这样就有可能读取到多次低电平,导致输出的信号不稳定。因此需要对按键进行消抖。

举个例子:

`timescale 1ns / 1ps
module key_test
(
	input                 clk,       
	input [3:0]           key,       
	output[3:0]           led        
);

reg[3:0] led_r;           
always@(posedge clk)
begin
	case(key)
		4'b1110:led_r[0]<=!led_r[0];
		4'b1101:led_r[1]<=!led_r[1];
		4'b1011:led_r[2]<=!led_r[2];
		4'b0111:led_r[3]<=!led_r[3];
		default:led_r<=led_r;
	endcase
end

assign led = led_r;

endmodule 

此段代码目的是四个按键对应四个LED灯。按键按下时,对应LED灯的状态翻转一次(从亮到灭或从灭到亮)。但是由于没有经过按键消抖,会发现LED灯常常不受控制。这就是因为按键抖动导致到多次读取到低电平,使得输出不稳定。

二.按键消抖原理

按键消抖即使为了解决上述的问题。在按键按下或者释放后,先延时一段时间(10ms~20ms),待信号稳定再进行读取

1.key_debounce.v(按键消抖模块)

module key_debounce(
	input            sys_clk,          //外部50M时钟
	input            sys_rst_n,        //外部复位信号,低有效
	
	input  [2:0]     key,              //外部按键输入,按下后为低电平
	output reg  key_flag,         	   //按键数据有效信号,即表示延时结束,按键已稳定
	output reg  [2:0]  key_value       //按键消抖后的数据  
	);

//reg define    
reg [19:0] delay_cnt;	//消抖延时的计数器
reg [2:0]  key_reg;		//按键值存储

//*****************************************************
//**                    main code
//*****************************************************
always @(posedge sys_clk or negedge sys_rst_n) begin 
	if (!sys_rst_n) 
	begin 
		key_reg   <= 3'b111;	//按键值复位,全为高电平
		delay_cnt <= 19'd0;		//计数器清零
	end
	else 
	begin
		key_reg <= key;	//非阻塞赋值,因此下行if判断中的key_reg仍为前一次的数据,而非此次的key
		if(key_reg != key)	//一旦检测到按键状态发生变化(有按键被按下或释放)
			delay_cnt <= 19'd1_000_000;  //给延时计数器重新装载初始值(计数时间为20ms)
		else if(key_reg == key) 
		begin  //在按键状态稳定时,计数器递减,开始20ms倒计时
			if(delay_cnt > 19'd0)
				delay_cnt <= delay_cnt - 1'b1;
			else
				delay_cnt <= delay_cnt;
		end           
	end   
end

always @(posedge sys_clk or negedge sys_rst_n) 
begin 
	if (!sys_rst_n) 
	begin 
		key_flag  <= 1'b0;	
		key_value <= 3'b111;	          
	end	 
	else 
	begin
		if(delay_cnt == 19'd1) //减到1而不是0的原因是:复位情况和无按键按下时cnt恒为零,则key_flag会一直为1
		begin   //同时,当计数器递减到1时,说明按键稳定状态维持了20ms
			key_flag  <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
			key_value <= key;  //并寄存此时按键的值
		end
		else 
		begin
			key_flag  <= 1'b0;	//延时未到,不给出有效信号
			key_value <= key_value; 
		end  
	end   
end
   
endmodule 

这种按键消抖方式,实际上是等待按键稳定后再进行20ms的延时进行确认。因为按键抖动时,计数器在不断重装载值。

2.led_control.v(LED控制模块)

module led_control(
      //input
      input        sys_clk,     //系统时钟
      input        sys_rst_n,   //复位信号,低电平有效
      
      input  key_flag,    //按键有效信号
      input  [2:0] key_value,	//消抖后的按键信号	
      output reg [2:0] led         //蜂鸣器控制信号  
  );
 
//*****************************************************
//**                    main code
//*****************************************************
always @ (posedge sys_clk or negedge sys_rst_n) 
begin
	if(!sys_rst_n)
		led <= 3'b000;
	else if(key_flag)  //判断按键是否有效按下
		case(key_value)
			3'b110:led[0]<=!led[0];
			3'b101:led[1]<=!led[1];   
			3'b011:led[2]<=!led[2];   
			default:led<=led;
		endcase
end	
    
endmodule 

3.top_key_led.v(主函数)

module top_key_led(
	input        sys_clk,       //时钟信号50Mhz
	input        sys_rst_n,     //复位信号
	
	input  [2:0]  key,           //按键信号       
	output [2:0] led           //蜂鸣器控制信号
	);
      
//wire define
wire [2:0] key_value;
wire key_flag;

//*****************************************************
//**                    main code
//*****************************************************

//例化按键消抖模块
key_debounce u_key_debounce(
    .sys_clk        (sys_clk),
    .sys_rst_n      (sys_rst_n),
    
    .key            (key),
    .key_flag       (key_flag),
    .key_value      (key_value)
    );
  
//例化蜂鸣器控制模块
led_control u_led_control(
    .sys_clk        (sys_clk), 
    .sys_rst_n      (sys_rst_n),
    
    .key_flag       (key_flag),      
    .key_value      (key_value),
    .led            (led)
    );
    
endmodule 

Verilog语法通过以上方式例化要使用的模块,类似于C语言中的函数调用。需要注意,例化模块需要给出一个例化的名字,如代码中的和u_key_debounceu_led_control,这点更像Java等面向对象语言中给类创建对象的操作。

RTL设计
在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

默默无闻小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值