状态机实现N位按键消抖

状态机实现N位按键消抖

1、原理

利用状态机实现按键的消抖,具体的原理可参考

(50条消息) 基于FPGA的按键消抖_fpga 按键消抖_辣子鸡味的橘子的博客-CSDN博客

状态机简介:

状态机分类可以主要分为两类:moore和mealy

根据三段式状态机最后一段的组合逻辑,根据状态机的输出是否与输出条件有关可以用来区分moore状态机和mealy状态机

若输出只与当前状态机有关,则为moore状态机

 always @*
    begin
        if(current_state == s4) dout = 1;
        else dout = 0;
    end
 

Moore状态机仅仅和当前状态有关

img

Mealy状态机:输出不仅取决于当前状态,还和输入有关;

同样是三段式描述,最后的输出为:

always @(*)
	begin
		if(reset) dout = 1'b0;
		else if( (current_state == s3)&&(din == 1'b1) ) dout = 1'b1;
		else dout = 1'b0;
	end
    

img

可见,输出不仅和当前状态和输入都有关系。

最后,Moore状态机和Mealy状态机可以相互转换。上述两个状态转移图实际上实现的是同一个功能,就是检测序列1101.

状态机按照段式分类,可分为:一段式、二段式、三段式

可参考:

(50条消息) 状态机详解(一段式、二段式、三段式)_状态机一段式二段式三段式_CuteBaBaKiller的博客-CSDN博客

image-20230727171608721

2、代码

module fsm_key_n#(parameter N = 4,parameter TIME_20MS = 1000_000)(
    input wire clk,
    input wire rst_n,
    input wire[N-1:0] key_in,

    output wire[N-1:0] key_out
);
reg[3:0] key_out_r;//中间信号
reg[24:0] cnt_20ms;//20ms计数器
//状态空间
parameter IDLE = 4'b0001,
			FILTER_DOWN = 4'b0010,
			DOWN = 4'b0100,
			FILTER_UP = 4'b1000;

reg[3:0] cstate;//现态
reg[3:0] nstate;//次态
reg[N-1:0] key_r0,key_r1,key_r2;//按键延时
reg flag;//检测下降沿和上升沿,寄存
//****************************************************************
//--状态转移条件定义
//****************************************************************
wire idle2filter_down;
wire filter_down2down;
wire down2filter_up;
wire filter_up2idle;
//****************************************************************
//--"计时开始结束条件
//****************************************************************
wire add_cnt_20ms;
wire end_cnt_20ms;

//****************************************************************
//--下降沿上升沿检测
//****************************************************************
assign nedge = |(~key_r1&key_r2);
assign podge = |(key_r1&key_r2);
//****************************************************************
//--状态转移条件约束
//****************************************************************
assign idle2filter_down = nedge && cstate == IDLE;
assign filter_down2down = end_cnt_20ms && cstate == FILTER_DOWN;
assign down2filter_up = podge && cstate == DOWN;
assign filter_up2idle = end_cnt_20ms && cstate == FILTER_UP;

//****************************************************************
//--"信号延时
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
      	key_r0 <= {N{1'b1}};
      	key_r1 <= {N{1'b1}};
      	key_r2 <= {N{1'b1}};
    end
    else begin
        key_r0<=key_in;
        key_r1<=key_r0;
        key_r2<=key_r1;
    end
end

//****************************************************************
//--"flag信号约束
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
      	flag<=1'b0;
    end
    else if(nedge || podge)begin
        flag<=1;
    end
    else if(end_cnt_20ms)begin
    	flag<=0;
    end
    else begin
    	flag<=flag;
    end
end
//****************************************************************
//--"20ms计数
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
       cnt_20ms<='d0;
    end
    else if(add_cnt_20ms)begin
        if(end_cnt_20ms)begin
            cnt_20ms <='d0;
        end
        else if(nedge)begin
            cnt_20ms <= 0;
        end
        else begin
        	cnt_20ms <= cnt_20ms + 1'b1;
        end
    end
    else begin
       cnt_20ms<=cnt_20ms;
    end
end
//****************************************************************
//--"20ms计数条件约束
//****************************************************************
assign add_cnt_20ms = flag;
assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == TIME_20MS - 1;

//****************************************************************
//--"三段式状态机,第一段,时序逻辑
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cstate<=IDLE;//初始当前状态为空闲
    end
    else begin
        cstate<=nstate;//次态赋值给现态
    end
end


//****************************************************************
//--"三段式状态机,第二段,组合逻辑,状态转移
//****************************************************************
always @(*) begin
    case(cstate)
        IDLE:begin
        	if(idle2filter_down)begin
        		nstate = FILTER_DOWN;
        	end
        	else begin
        		nstate = cstate;
        	end
        end
        FILTER_DOWN:
        begin
        	if(filter_down2down)begin
        	    nstate = DOWN;		
        	end
        	else begin
        	    nstate = cstate;	
        	end    
        end
        		
        DOWN:begin
        	if(down2filter_up)begin
        	    nstate = FILTER_UP;	
        	end
        	else begin
        	    nstate = cstate;		
        	end
        end

        FILTER_UP:begin
        	if(filter_up2idle)begin
        	    nstate = IDLE;		
        	end
        	else begin
        	    nstate = cstate;		
        	end
        end
        default:
            nstate = cstate;
    endcase
end

//****************************************************************
//--"有限状态机,第三段,时序逻辑
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
       	key_out_r<={N{1'b0}};
    end
    else if(filter_down2down)begin
        key_out_r<=~key_r1;
    end
    else begin
        key_out_r<={N{1'b0}};
    end
end
assign key_out = key_out_r;

endmodule

3、仿真代码

`timescale 1ns/1ns
module fsm_key_tb();

reg clk;
reg rst_n;
reg[3:0] key;
reg[3:0] delay;

wire[3:0] key_r;
parameter SYS_CLK = 20;
parameter TIME_20MS = 10;
parameter N = 4;
always #(SYS_CLK/2) clk = ~clk;

task task_init;
	begin
		clk=1'b0;
		rst_n=1'b0;
		#(2*SYS_CLK);
		rst_n=1'b1;
		key = 4'b1111;
		#(2*SYS_CLK);
	end
endtask

task task_key;
	input[3:0] key_in;
	output[3:0] key_out;
	begin
		key_out[0] = ~key_in[0];
		key_out[2] = ~key_in[2];
		key_out[3] = key_in[3];
		key_out[1] = key_in[1];
	end
endtask

initial begin
	task_init();

	repeat(10)begin
		repeat (20) begin
			task_key(key,key);
	   		// key[0] = ~key[0];
	   		// key[2] = ~key[2];
	   		delay = {$random()}%4;
	   		#(SYS_CLK*delay);
		end
		task_key(key,key);
		// key[0] = ~key[0];
		// key[2] = ~key[2];
		//wait(inst_fsm_key.end_cnt_20ms);
		#(30*SYS_CLK);
	end
	$stop;
end

fsm_key_n #(
		.N(N),
		.TIME_20MS(TIME_20MS)
	) inst_fsm_key (
		.clk     (clk),
		.rst_n   (rst_n),
		.key_in  (key),
		.key_out (key_r)
	);

endmodule

4、仿真结果

image-20230727171418129

5、总结

使用状态机进行按键消抖,可以经消抖分为四个部分,空闲状态、下降沿状态、按下状态、上升沿状态,这几个状态使用状态机进行按键消抖,可以更好的理解消抖的原理和过程。状态机的规范编写也是提升自己理解时序,理解逻辑的好的方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/51587.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Virtualbox虚拟机中Ubuntu忘记密码

1、首先重新启动Ubuntu系统&#xff0c;鼠标快速点一下Virtualbox虚拟机窗口获取焦点&#xff0c;然后按住shift键&#xff0c;以调出grub启动菜单。 2、根据提示按下键盘E键进入编辑模式&#xff0c;向下移动光标&#xff0c;将如下"ro quiet splash $vt_handoff"部…

软件测试面试【证券项目公司】

这家公司是做证券项目的&#xff0c;约的9点钟&#xff0c;路程还是有点遥远&#xff0c;转了一趟公交两趟地铁&#xff0c;精力都花在了路上&#xff0c;感觉有点累&#xff0c;以下是今天得面试流程。 到公司前台给我了一张面试表&#xff0c;写完之后就是等待面试。一共面试…

GAMES101 笔记 Lecture13 光线追踪1

目录 Why Ray Tracing?(为什么需要光线追踪&#xff1f;)Basic Ray Tracing Algorithm(基础的光线追踪算法)Ray Casting(光线的投射)Generating Eye Rays(生成Eye Rays) Recursive(Whitted-Styled) Ray Tracing Ray-Surface Intersection(光线和平面的交点)Ray Rquation(射线方…

PC音频框架学习

1.整体链路 下行播放&#xff1a; App下发音源→CPU Audio Engine 信号处理→DSP数字信号处理→Codec DAC→PA→SPK 上行录音&#xff1a; MIC拾音→集成运放→Codec ADC→DSP数字信号处理→CPU Audio Engine 信号处理→App 2.硬件 CPU PCH DSP(可选) Codec PA SPKbox MIC…

spring项目中idea提示Application context not configured for this file

今天在重构项目的时候&#xff0c;碰到一个问题。就是在spring底下&#xff0c;有一个包里面的所有配置类&#xff0c;在idea的开发工具类底下提示&#xff0c;Application context not configured for this file&#xff0c;如图所示 一开始以为是警告&#xff0c;不予处理&am…

【NLP】语音识别 — GMM, HMM

一、说明 在语音识别的深度学习&#xff08;DL&#xff09;时代之前&#xff0c;HMM和GMM是语音识别的两项必学技术。现在&#xff0c;有将HMM与深度学习相结合的混合系统&#xff0c;并且有些系统是免费的HMM。我们现在有更多的设计选择。然而&#xff0c;对于许多生成模型来说…

C++之文件操作

1.C文件操作 C中文件操作头文件:fstream。   文件类型&#xff1a;文件文件和二进制文件。 文件操作三大类&#xff1a;     ofstream 写操作     ifstream 读操作     fstream:读写操作 文件打开方式&#xff1a; 标志说明ios::in只读ios::out只写,文件不存在则…

JVM详解(超详细)

目录 JVM 的简介 JVM 执行流程 JVM 运行时数据区 由五部分组成 JVM 的类加载机制 类加载的过程(五个) 双亲委派模型 类加载器 双亲委派模型的优点 JVM 中的垃圾回收策略 GC GC 中主要分成两个阶段 死亡对象的判断算法 引用计数算法 可达性分析算法 垃圾回收算…

【设计模式——学习笔记】23种设计模式——组合模式Composite(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入学校院系展示 介绍基本介绍使用场景登场角色 案例实现案例1类图代码实现 案例2类图代码实现拓展 组合模式在JDK的HashMap源码中的应用组合模式总结文章说明 案例引入 学校院系展示 编写程序展示一个学校院系结构: 需求是这样&#xff0c;要在一个页面中展示…

EXCEL,如何比较2个表里的数据差异(使用数据透视表)

目录 1 问题: 需要比较如下2个表的内容差异 1.1 原始数据喝问题 1.2 提前总结 2 使用EXCEL公式方法 2.1 新增辅助列&#xff1a; 辅助index 2.2 具体公式 配合条件格式 使用 3 数据透视表方法 3.1 新增辅助列&#xff1a; 辅助index 3.2 需要先打开 数据透视表向导 …

CMU 15-445 -- Multi-Version Concurrency Control - 16

CMU 15-445 -- Multi-Version Concurrency Control - 16 引言MVCCExample #1Example #2小结 Design DecisionsConcurrency Control ProtocolVersion StorageAppend-Only StorageTime-Travel StorageDelta Storage Garbage CollectionTuple-Level GCTransaction-Level GC Index …

linux系统安装mysql

背景 之前用docker安装mysql&#xff0c;受限太多&#xff0c;这次不用docker直接安装。 参考文章 linux系统安装mysql 文章写的很细&#xff0c;亲测有效。 问题记录 不过存在一个小问题&#xff0c;这里记录一下自己的解决方法 问题&#xff1a;安装完mysql&#xff0c;启…

MD-MTSP:成长优化算法GO求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、成长优化算法GO 成长优化算法&#xff08;Growth Optimizer&#xff0c;GO&#xff09;由Qingke Zhang等人于2023年提出&#xff0c;该算法的设计灵感来源于个人在成长过程中的学习和反思机制。学习是个人通过从外部世界获取知识而成长的过程&#xff0c;反思是检查个体自…

【物联网无线通信技术】UWB定位从理论到实现(DW1000)

超宽带&#xff08;UWB&#xff09;是一种基于IEEE 802.15.4a和802.15.4z标准的无线电技术&#xff0c;可以非常精确地测量无线电信号的飞行时间&#xff0c;从而实现厘米级精度的距离/位置测量。UWB技术除了提供定位功能外&#xff0c;它本身是一种通信技术&#xff0c;其提供…

Labelme制作COCO格式的图像语义分割数据集

1.按照labelme工具地址先配置安装labelme&#xff1a;GitHub - wkentaro/labelme: Image Polygonal Annotation with Python (polygon, rectangle, circle, line, point and image-level flag annotation). 2.给自己的数据集画多边形框-Create Polygons 每张图像画完框后&#…

[个人笔记] vCenter设置时区和NTP同步

VMware虚拟化 - 运维篇 第三章 vCenter设置时区和NTP同步 VMware虚拟化 - 运维篇系列文章回顾vCenter设置时区和NTP同步&#xff08;附加&#xff09;ESXi设置alias参考链接 系列文章回顾 第一章 vCenter给虚机添加RDM磁盘 第二章 vCenter回收活跃虚拟机的剩余可用空间 vCente…

linux+Jenkins+飞书机器人发送通知(带签名)

文章目录 &#x1f31e;如何使用&#x1f33b;在linux 上安装python 环境&#x1f33b;发送消息python脚本&#x1f98b;把脚本上传倒linux上&#x1f98b;jenkins 上执行脚本 &#x1f31e;如何使用 自定义机器人使用指南飞书官网https://open.feishu.cn/document/client-doc…

ChatGPT炒股:爬取股票官方微信公众号的新闻资讯

上市公司的微信公众号&#xff0c;现在已经成为官网之外最重要的官方信息发布渠道。有些不会在股票公告中发布的消息&#xff0c;也会在微信公众号进行发布。所以&#xff0c;跟踪持仓股票的公众号信息&#xff0c;非常重要。 下面&#xff0c;以贝特瑞的官方公众号“贝特瑞新…

beego验证码(配置到redis存储)

我们定义一个全局变量用于存储redis连接 RedisDb *redis.Client 然后连接 redis 这一块我们将redis信息写到app.conf文件里了&#xff1a; redisDb 1 redisAddr "127.0.0.1:6379" redisPwd "" package initializeimport ("beego_learning/global&q…

经典的数组和指针结合的OJ题

一、合并两个有序数组 leetcode链接 题目描述&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递…