【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)

这篇具有很好参考价值的文章主要介绍了【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🎉欢迎来到FPGA专栏~按键消抖模块设计与验证


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机

【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机

【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机

一、效果演示

🥝模块设计:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


🥝按键消抖模块的完整代码,可直接使用:

//
//模块:按键消抖模块
//key_state:输出消抖之后按键的状态
//key_flag:按键消抖结束时产生一个时钟周期的高电平脉冲
//
module KeyFilter(
	input Clk,
	input Rst_n,
	input key_in,
	output reg key_flag,
	output reg key_state
);

	//按键的四个状态
	localparam
		IDLE 		= 4'b0001,
		FILTER1 	= 4'b0010,
		DOWN 		= 4'b0100,
		FILTER2 	= 4'b1000;

	//状态寄存器
	reg [3:0] curr_st;
	
	//边沿检测输出上升沿或下降沿
	wire pedge;
	wire nedge;
	
	//计数寄存器
	reg [19:0]cnt;
	
	//使能计数寄存器
	reg en_cnt;
	
	//计数满标志信号
	reg cnt_full;//计数满寄存器
	
//------<边沿检测电路的实现>------
	//边沿检测电路寄存器
	reg key_tmp0;
	reg key_tmp1;
	
	//边沿检测
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			key_tmp0 <= 1'b0;
			key_tmp1 <= 1'b0;
		end
		else begin
			key_tmp0 <= key_in;
			key_tmp1 <= key_tmp0;
		end	
	end
		
	assign nedge = (!key_tmp0) & (key_tmp1);
	assign pedge = (key_tmp0)  & (!key_tmp1);

//------<状态机主程序>------	
	//状态机主程序
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			curr_st <= IDLE;
			en_cnt <= 1'b0;
			key_flag <= 1'b0;
			key_state <= 1'b1;
		end
		else begin
			case(curr_st)
				IDLE:begin
					key_flag <= 1'b0;
					if(nedge)begin
						curr_st <= FILTER1;
						en_cnt <= 1'b1;
					end
					else
						curr_st <= IDLE;
				end
				
				FILTER1:begin
					if(cnt_full)begin
						key_flag <= 1'b1;
						key_state <= 1'b0;
						curr_st <= DOWN;
						en_cnt <= 1'b0;
					end	
					else if(pedge)begin
						curr_st <= IDLE;
						en_cnt <= 1'b0;
					end
					else
						curr_st <= FILTER1;
				end
				
				DOWN:begin
					key_flag <= 1'b0;
					if(pedge)begin
						curr_st <= FILTER2;
						en_cnt <= 1'b1;
					end
					else
						curr_st <= DOWN;
				end
				
				FILTER2:begin
					if(cnt_full)begin
						key_flag <= 1'b1;
						key_state <= 1'b1;
						curr_st <= IDLE;
						en_cnt <= 1'b0;
					end	
					else if(nedge)begin
						curr_st <= DOWN;
						en_cnt <= 1'b0;
					end
					else
						curr_st <= FILTER2;
				end
				
				default:begin
					curr_st <= IDLE;
					en_cnt <= 1'b0;
					key_flag <= 1'b0;
					key_state <= 1'b1;
				end
			endcase
		end
	end
	
//------<20ms计数器>------		
	//20ms计数器
	//Clk 50_000_000Hz
	//一个时钟周期为20ns
	//需要计数20_000_000 / 20 = 1_000_000次
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 20'd0;
		else if(en_cnt)
			cnt <= cnt + 1'b1;
		else
			cnt <= 20'd0;
	end
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt_full <= 1'b0;
		else if(cnt == 999_999)
			cnt_full <= 1'b1;
		else
			cnt_full <= 1'b0;
	end
	
endmodule


🥝RTL视图:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


🥝状态转移:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


🥝仿真结果:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


二、模块设计

🥝模块设计:

信号 作用
clk 时钟信号输入
rst_n 复位信号输入
key_in 按键信号输入
key_flag 消抖结束之后的标志位
key_state 消抖结束之后按键的状态

【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


🥝上升沿检测电路:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


🥝下降沿检测电路:

【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


🥝边沿检测电路的实现:
检测到下降沿,nedge输出高电平;检测到上升沿,pedge输出高电平。

//------<边沿检测电路的实现>------
//边沿检测电路寄存器
reg key_tmp0;
reg key_tmp1;

//边沿检测
always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)begin
		key_tmp0 <= 1'b0;
		key_tmp1 <= 1'b0;
	end
	else begin
		key_tmp0 <= key_in;
		key_tmp1 <= key_tmp0;
	end	
end
	
assign nedge = (!key_tmp0) & (key_tmp1);//检测到下降沿,nedge输出高电平
assign pedge = (key_tmp0)  & (!key_tmp1);//检测到上升沿,pedge输出高电平

🥝一段式状态机设计:
按键的四种状态:

//按键的四个状态
localparam
	IDLE 		= 4'b0001,
	FILTER1 	= 4'b0010,
	DOWN 		= 4'b0100,
	FILTER2 	= 4'b1000;

计数器:

//------<20ms计数器>------		
//20ms计数器
//Clk 50_000_000Hz
//一个时钟周期为20ns
//需要计数20_000_000 / 20 = 1_000_000次

//计数寄存器
reg [19:0]cnt;

//使能计数寄存器
reg en_cnt;

//计数满标志信号
reg cnt_full;//计数满寄存器
	
always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)
		cnt <= 20'd0;
	else if(en_cnt)
		cnt <= cnt + 1'b1;
	else
		cnt <= 20'd0;
end

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

状态机主程序:

//------<状态机主程序>------	
//状态机主程序
always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)begin
		curr_st <= IDLE;
		en_cnt <= 1'b0;
		key_flag <= 1'b0;
		key_state <= 1'b1;
	end
	else begin
		case(curr_st)
			IDLE:begin
				key_flag <= 1'b0;
				if(nedge)begin
					curr_st <= FILTER1;
					en_cnt <= 1'b1;
				end
				else
					curr_st <= IDLE;
			end
			
			FILTER1:begin
				if(cnt_full)begin
					key_flag <= 1'b1;
					key_state <= 1'b0;
					curr_st <= DOWN;
					en_cnt <= 1'b0;
				end	
				else if(pedge)begin
					curr_st <= IDLE;
					en_cnt <= 1'b0;
				end
				else
					curr_st <= FILTER1;
			end
			
			DOWN:begin
				key_flag <= 1'b0;
				if(pedge)begin
					curr_st <= FILTER2;
					en_cnt <= 1'b1;
				end
				else
					curr_st <= DOWN;
			end
			
			FILTER2:begin
				if(cnt_full)begin
					key_flag <= 1'b1;
					key_state <= 1'b1;
					curr_st <= IDLE;
					en_cnt <= 1'b0;
				end	
				else if(nedge)begin
					curr_st <= DOWN;
					en_cnt <= 1'b0;
				end
				else
					curr_st <= FILTER2;
			end
			
			default:begin
				curr_st <= IDLE;
				en_cnt <= 1'b0;
				key_flag <= 1'b0;
				key_state <= 1'b1;
			end
		endcase
	end
end

三、仿真测试

3.1 常规编写

`timescale 1ns/1ns
`define clock_period 20

module KeyFilter_tb;

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

	KeyFilter KeyFilter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	initial Clk = 1;
	always#(`clock_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		key_in = 1'b1;
		#(`clock_period*10);
		Rst_n = 1'b1;
		#(`clock_period*10 + 1);
		
		key_in = 0;#1000;
		key_in = 1;#2000;
		key_in = 0;#1400;
		key_in = 1;#2600;
		key_in = 0;#1300;
		key_in = 1;#200;
		key_in = 0;#20000100;
		#50000000;
		
		key_in = 1;#2600;
		key_in = 0;#1000;
		key_in = 1;#2000;
		key_in = 0;#1400;
		key_in = 1;#2600;
		key_in = 0;#1300;
		key_in = 1;#200;
		key_in = 1;#20000100;
		#50000000;

		$stop;
	
	end
	
endmodule

仿真结果:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


3.2 task编写

`timescale 1ns/1ns
`define clock_period 20

module KeyFilter_tb;

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

	KeyFilter KeyFilter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	initial Clk = 1;
	always#(`clock_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		key_in = 1'b1;
		#(`clock_period*10);
		Rst_n = 1'b1;
		#(`clock_period*10 + 1);
		#30000;
		
		PressKey; #10000;
		PressKey; #10000;
		PressKey; #10000;
		
		$stop;
	end
	
	reg [15:0]myrand;
	
	task PressKey;
		begin
			//50次随机时间按下抖动
			repeat(50)begin
				myrand = {$random}%65536;//0~65535
				#myrand key_in = ~key_in;
			end
			key_in = 0;
			#50_000_000;//按下稳定
			
			//50次随机时间释放抖动
			repeat(50)begin
				myrand = {$random}%65536;//0~65535
				#myrand key_in = ~key_in;
			end
			key_in = 1;
			#50_000_000;//释放稳定
		end
	endtask
	
endmodule

注意$random随机函数的用法:

$random这一系统函数可以产生一个有符号的32bit随机整数。一般的用法是 $random%b,其中 b>0。这样就会生成一个范围在(-b+1):(b-1)中的随机数。如果只得到正数的随机数,可采用{$random}%b 来产生。

myrand = {$random}%65536;//0~65535

上述语句的作用即是产生了0~65535之间的随机数。

通过repeat语句循环50次,就产生了50次不同的延时效果:

repeat(50)begin
	myrand = {$random}%65536;//0~65535
	#myrand key_in = ~key_in;
end

仿真结果:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机


四、仿真模型

编写key_model并添加到测试激励文件中:

`timescale 1ns/1ns

module key_model(key);
	
	output reg key;
	
	reg [15:0]myrand;
	
	initial begin
		key = 1'b1;
		PressKey; #10000;
		PressKey; #10000;
		PressKey; #10000;
		
		$stop;
	end
	
	task PressKey;
		begin
			//50次随机时间按下抖动
			repeat(50)begin
				myrand = {$random}%65536;//0~65535
				#myrand key = ~key;
			end
			key = 0;
			#50_000_000;//按下稳定
			
			//50次随机时间释放抖动
			repeat(50)begin
				myrand = {$random}%65536;//0~65535
				#myrand key = ~key;
			end
			key = 1;
			#50_000_000;//释放稳定
		end
	endtask	

endmodule

修改KeyFilter_tb:

`timescale 1ns/1ns
`define clock_period 20

module KeyFilter_tb;

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

	KeyFilter KeyFilter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	key_model key_model0(.key(key_in));
	
	initial Clk = 1;
	always#(`clock_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		#(`clock_period*10);
		Rst_n = 1'b1;
		#(`clock_period*10 + 1);
	end
	
endmodule

整个激励文件的内部结构:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机
仿真结果:
【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机

【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机

🧸结尾文章来源地址https://www.toymoban.com/news/detail-658798.html


  • ❤️ 感谢您的支持和鼓励! 😊🙏
  • 📜您可能感兴趣的内容:
  • 【FPGA】串口通信讲解-状态机判断数据值
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)
  • 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
  • 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制
    【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现),FPGA学习之旅,fpga开发,学习,FPGA,按键消抖,Verilog HDL,一段式状态机

到了这里,关于【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA学习——按键控制LED流水灯(附源码 无按键消抖版本)

    在博主的cyclone4开发板上一共有4个按键,本次实验的目的是为了实现每按下一次按键,都会使开发板上的4个LED灯切换一次状态,博主一共设计了四种状态,分别是: 按键 状态 按键1按下 自右向左的流水灯 按键2按下 自左向右的流水灯 按键3按下 四灯常亮 按键4按下 四灯闪烁

    2024年02月06日
    浏览(31)
  • 【FPGA零基础学习之旅#7】BCD计数器设计

    🎉欢迎来到FPGA专栏~BCD计数器设计 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 顶层模块中的BCD模块级联: Verilog实现

    2024年02月08日
    浏览(34)
  • FPGA开发:按键消抖

    相关阅读 FPGA开发专栏 https://blog.csdn.net/weixin_45791458/category_12388695.html?spm=1001.2014.3001.5482         按键是FPGA开发板上的重要交互元件,因为按键的内部的结构设计,在按下和松开按键时,按键会无法避免地产生机械抖动,因此要对按键输入进行特殊处理,否则可能会因为机械

    2024年02月15日
    浏览(38)
  • FPGA按键消抖

    按键是输入设备,一般来说,按键在没有按下的时候是高电平;当按键按下的时候,为低电平。 在 DE2-70 User Manual 中 Each switch provides a high logic level (3.3 volts) when it is not pressed, and provides a low logic level (0 volts) when depressed. Since the pushbutton switches are debounced, they are appropriate for use

    2024年02月15日
    浏览(40)
  • 基于FPGA的按键消抖

    按键抖动:按键抖动通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。当按下一次按键,可能在A点检测到一

    2024年02月16日
    浏览(35)
  • 二、13【FPGA】按键消抖

    学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。 学习视频:是根据野火FPGA视频教程——第十六讲 https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3 按键常常作为系统复位信号和控制信号的外部输入,主要分为自锁按键、机械按键和薄膜按键等。开发

    2023年04月26日
    浏览(33)
  • 【FPGA入门】第五篇、按键消抖

    目录 第一部分、按键抖动现象 第二部分、消抖思路及代码 1、简单的按键消抖思路 2、实际按键消抖思路 3、实际按键消抖模块代码 第三部分、总结         只要学习过单片机的都会知道,按键在按下去和松开的那个瞬间都存在抖动,在单片机消除抖动最简单的方式就是 延

    2024年02月11日
    浏览(25)
  • verilog-实现按键消抖模块

    轻触按键:相当于是一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通和断开。 说明: 如上图,产生的抖动次数以及间隔时间均是不可预期的,这就需要通过滤波来消除抖动可能对外部其他设备造成的影响。一

    2024年02月03日
    浏览(26)
  • Arduino程序设计(四)按键消抖+按键计数

    本文主要介绍两种按键控制LED实验: 第一种是采用软件消抖的方法检测按键按下的效果; 第二种是根据按键按下次数,四个LED灯呈现不同的流水灯效果。 按键在按下时,由于机械和物理特定的原因,经常会产生一些开关变换,而这些变换会让程序误认为是短时间内进行了多

    2024年02月10日
    浏览(64)
  • 【FPGA零基础学习之旅#9】状态机基础知识

    🎉欢迎来到FPGA专栏~状态机基础知识 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🔸 Hello状态机例程 : RTL视图: 状态

    2024年02月16日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包