基于FPGA的数字钟——(二)按键消抖模块设计
发布日期:2021-05-07 22:56:10 浏览次数:23 分类:精选文章

本文共 3551 字,大约阅读时间需要 11 分钟。

基于FPGA的数字钟——(二)按键消抖模块

1、硬件原理

按键按下时会有随机的抖动,因此需要在抖动期过后再进行按键状态的判断。

2、原理实现

按键引脚检测电平跳变,跳变时进行计数,计数一定时间后再判断电平·高低以判断是抖动还是真实按下。检测按键放开同理。

3、FPGA实现

设计一个状态机,有以下几个状态:IDLE(放开),FILTER0(下降沿滤波),DOWN(按下),FILTER1(上升沿滤波)。

消抖计数器计数周期为50000个时钟周期,即50000*20=1000000ns=1ms

verilog代码

//// Company: NanJing University of Information Science & Technology// Engineer: Yang Cheng Yu// // Create Date: 2019/12/29 15:55:40// Design Name: key_debounce// Module Name: key_debounce// Project Name: Clock// Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:// //module key_debounce#(	parameter BEBON_CNT = 50000//消抖计数器)(	input clk,	input rst,	input key_in,	output reg key_press,	output reg key_up);	reg[15:0] debounce_cnt;//1ms计数器	reg cnt_en;	reg cnt_full;	reg key_temp0;	reg key_temp1;	wire nedge;//按键下降沿	wire pedge;//按键上升沿	reg[3:0] state;	localparam IDLE = 4'b0001;	localparam FILTER0 = 4'b0010;	localparam DOWN = 4'b0100;	localparam FILTER1 = 4'b1000;	always@(posedge clk or negedge rst)begin		if(!rst)begin			key_temp0 <= 1'b1;			key_temp1 <= 1'b1;		end		else begin			key_temp0 <= key_in;			key_temp1 <= key_temp0;		end	end	assign nedge = (!key_temp0)&(key_temp1);	assign pedge = (key_temp0)&(!key_temp1);		always@(posedge clk or negedge rst)begin		if(!rst)begin			debounce_cnt <= 16'd1;			cnt_full <= 1'b0;		end		else			if(cnt_en)				if(debounce_cnt==BEBON_CNT)begin					debounce_cnt <= 16'd1;					cnt_full <= 1'b1;				end				else begin					debounce_cnt <= debounce_cnt + 1'b1;					cnt_full <= 1'b0;				end			else begin				debounce_cnt <= 16'd1;				cnt_full <= 1'b0;			end	end			always@(posedge clk or negedge rst)begin		if(!rst)begin			state <= IDLE;		end		else			case(state)				IDLE:begin					if(nedge)						state <= FILTER0;					else						state <= IDLE;				end				FILTER0:begin					if(cnt_full)						if(key_temp0==1'b0)//计时结束按键还按着							state <= DOWN;						else							state <= IDLE;					else						state <= FILTER0;				end				DOWN:begin					if(pedge)						state <= FILTER1;					else						state <= DOWN;				end				FILTER1:begin					if(cnt_full)						if(key_temp0==1'b1)//计数结束后按键还放开							state <= IDLE;						else							state <= DOWN;					else						state <= FILTER1;				end				default:					state <= IDLE;			endcase			end		always@(posedge clk or negedge rst)begin		if(!rst)begin			key_press <= 1'b0;			key_up <= 1'b1;			cnt_en <= 1'b0;		end		else			case(state)				IDLE:begin					key_press <= 1'b0;					key_up <= 1'b1;					cnt_en <= 1'b0;				end				FILTER0:begin					key_press <= 1'b0;					key_up <= 1'b1;					cnt_en <= 1'b1;				end				DOWN:begin					key_press <= 1'b1;					key_up <= 1'b0;					cnt_en <= 1'b0;				end				FILTER1:begin					key_press <= 1'b1;					key_up <= 1'b0;					cnt_en <= 1'b1;				end				default:begin					key_press <= 1'b0;					key_up <= 1'b1;					cnt_en <= 1'b0;				end			endcase				endendmodule

状态机转移图

在这里插入图片描述

testbench代码

仿真时缩短了计数器的计数周期为500个clk,只是为了让仿真跑快一点,计数50000个clk仿真要很久。

`timescale 1ns/1ps`define clock_period 20module key_debonce_tb;	reg clk;	reg rst;	reg key_in;	wire key_press;	wire key_up;key_debounce#(	.BEBON_CNT(500)//消抖计数器)key_debounce(	.clk(clk),	.rst(rst),	.key_in(key_in),	.key_press(key_press),	.key_up(key_up));	initial clk = 1;	always#(`clock_period/2)clk = ~clk;		initial begin		rst = 0;		key_in = 1;		#(`clock_period*20);		rst = 1;		key_in = 1;		#(`clock_period*100);		key_in = 0;		#(`clock_period*10);//一次抖动		key_in = 1;		#(`clock_period*500)				key_in = 0;		#(`clock_period*1000);//一次成功按下		key_in = 1;		#(`clock_period*1000);//一次成功放开		$stop;	endendmodule

仿真波形图

在这里插入图片描述

上一篇:SPI主机实现
下一篇:基于FPGA的数字钟——(一)串口通信模块

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年03月28日 15时17分43秒