状态机实现N位按键消抖

这篇具有很好参考价值的文章主要介绍了状态机实现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状态机仅仅和当前状态有关

状态机实现N位按键消抖,fpga开发

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

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

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

状态机实现N位按键消抖,fpga开发

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

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

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

可参考:

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

状态机实现N位按键消抖,fpga开发

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、仿真结果

状态机实现N位按键消抖,fpga开发

5、总结

使用状态机进行按键消抖,可以经消抖分为四个部分,空闲状态、下降沿状态、按下状态、上升沿状态,这几个状态使用状态机进行按键消抖,可以更好的理解消抖的原理和过程。状态机的规范编写也是提升自己理解时序,理解逻辑的好的方式文章来源地址https://www.toymoban.com/news/detail-620114.html

到了这里,关于状态机实现N位按键消抖的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • FPGA入门学习笔记(十三)Vivado实现按键消抖

    四种状态 按键未按下:静止状态呈高电平; 按下过程中:抖动状态呈高低电平; 按键已按下:静止状态呈低电平; 释放过程中:抖动状态呈高低电平。 按键消抖思路 :区别于单片机使用20ms延时判断电平正负,FPGA中采用电平保持计时,若时间长度超过20ms则认为发生了一次

    2024年02月04日
    浏览(65)
  • 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日
    浏览(51)
  • 基于FPGA的按键消抖

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

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

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

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

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

    2024年02月11日
    浏览(40)
  • FPGA拾忆_(10):按键控制蜂鸣器_边沿检测_按键消抖

    1.硬件特征: 轻触式(回弹式)按键         略 蜂鸣器: 分为蜂鸣器按照结构原理不同可分为压电式蜂鸣器和电磁式蜂鸣器。 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、 阻抗匹配器及共鸣箱、外壳等组成; 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组

    2024年04月10日
    浏览(38)
  • FPGA学习——按键控制LED流水灯(附源码 无按键消抖版本)

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

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

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

    2024年02月03日
    浏览(40)
  • verilog实现滚动显示学号(含按键消抖)

    经过了前前后后将近十个小时的时间,总算能够正确上板并写完了最终的实验报告。花费了我大量时间的实验我觉得有必要记录并分享出来。声明: 本人写verilog的能力不强,看我花了这么多时间就知道了,如果代码有问题感谢指正,代码是在这位学长的基础上修改的 零时的

    2024年02月04日
    浏览(33)
  • 学习笔记|按键原理|消抖|按键点灯的4种模式|STC32G单片机视频开发教程(冲哥)|第七集:按键点灯

    来源:爱问知识人:sos用灯光怎么表示 三短三长三短 SOS作为世界上通用的求救信号,如果用灯光信号来表示,三短亮代表字母S,三长亮代表字母O,再接着的三短亮代表S。 灯的长亮时间是短亮时间的三倍,而短亮时间则与LED两次点亮的间隔时间相同,字母与下一个字母间也有

    2024年02月12日
    浏览(45)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包