状态机按键消抖电路设计
按键消抖电路设计
- 1. 什么是按键抖动
- 2. 消抖电路设计思路
- 3. 代码实现
- 4. 仿真测试
- 4.1. initial语句块赋值
- 4.2. 调用task任务封装赋值并调用$random函数
重新补充一下,
这里的消抖,可以看作开关的消抖,开关闭合和释放都要进行消抖处理,并且中间会保持一段时间。
而按键的消抖,按下释放是连着的,这一个过程会发出一个脉冲信号,证明按键按下过
1. 什么是按键抖动
实际的拨动开关和按键都是机械式的设备,在状态改变时可能会出现来回抖动多次导致状态不稳定的情况,通常抖动的持续时间不超过20ms。消抖电路的目的就是滤去这段时间内的抖动信号。
2. 消抖电路设计思路
使用有限状态机的思想,当输入信号稳定20ms后才改变抖动以后的输出值。假定使用的系统时钟频率为50HMz,要等待20ms的时间,那么就使用计数器数1_000_000个clk,解决延时问题。
按照等待延时的思路,可以这样设计:检测到按键key_in按下,启动计数器,等到20ms后检测key_in是否为0,若为0,表明按键按下状态稳定,关闭计数器,然后等待按键key_in释放;当检测到key_in释放出现上升沿,再次启动计数器,20ms后检测key_in是否为1,若为1,表明按键已释放,一次完整的按键过程结束。 每20ms检测完毕后,输出一个flag脉冲。
为了实现按键消抖,考虑到两种情况,按下需要消抖,释放需要消抖。状态机分为4个状态,两个稳定状态和两个消抖状态
IDLE:空闲状态,默认按键不按下为稳定高电平
FILTER_DOWN:按键按下消抖状态
DOWN:按键按下稳定状态
FILTER_UP:按键释放消抖状态
消抖模块端口设计
3. 代码实现
module key_filter(output reg key_flag, // 消抖完毕输出脉冲output reg key_state, // 按键状态输出input wire clk, // 50MHz时钟input wire rst,input wire key_in);// 状态声明parameter IDLE = 4'b0001;parameter FILTER_DOWN = 4'b0010; parameter DOWN = 4'b0100;parameter FILTER_UP = 4'b1000;reg [3:0] next_state;reg key_temp; // wire key_nedge; //wire key_pedge; //reg en_counter; // 计数器使能信号reg [19:0] counter; // 计数1_000_000次// 边沿检测电路// 按键信号属于异步信号,在状态转移中需要对按键边沿敏感,所以先采用一级D触发器将key_in与clk同步,产生pedge和nedge信号always @ (posedge clk)key_temp <= key_in; // 暂存上一个按键状态assign key_nedge = (key_temp) && (!key_in); // 下降沿检测assign key_pedge = (!key_temp) && (key_in); // 上升沿检测// 带使能的计数器,实现20ms延时always @ (posedge clk) beginif (rst == 1'b0) begincounter <= 0;end else if (en_counter == 1'b1) begincounter <= counter + 1;end else begincounter <= 0;endend// 状态机模块always @ (posedge clk or negedge rst) beginif (rst == 1'b0) beginnext_state <= IDLE;en_counter <= 1'b0;key_flag <= 1'b0;key_state <= 1'b1;end else begincase (next_state)IDLE: beginkey_flag <= 1'b0;key_state <= 1'b1;if (key_nedge) beginnext_state <= FILTER_DOWN;en_counter <= 1'b1;end else beginnext_state <= IDLE;end endFILTER_DOWN: beginif (counter >= 20'd999_999) begin // 20ms时间到key_flag <= 1'b1; // flag输出一个高脉冲,进入稳定状态en_counter <= 1'b0; // 计数器不使能next_state <= DOWN;end else if (key_pedge) begin // 20ms内检测到有上升沿en_counter <= 1'b0; //计数器不使能,保持空闲状态next_state <= IDLE;endendDOWN: beginkey_flag <= 1'b0;key_state <= 1'b0;if (key_pedge) beginnext_state <= FILTER_UP;en_counter <= 1'b1;end else beginnext_state <= DOWN;end endFILTER_UP: beginif (counter >= 20'd999_999) begin // 20ms时间到key_flag <= 1'b1; // flag输出一个高脉冲,进入稳定状态en_counter <= 1'b0; // 计数器不使能next_state <= IDLE;end else if (key_nedge) begin // 20ms内检测到有下降沿en_counter <= 1'b0; // 计数器不使能,保持按下稳定状态next_state <= DOWN;endenddefault: beginnext_state <= IDLE;endendcaseendendendmodule
4. 仿真测试
4.1. initial语句块赋值
`define clk_period 20 //100M系统时钟module key_filter_tb();reg clk; //50M时钟信号reg rst; //低电平复位reg key_in; //按键输入wire key_flag; //消抖完毕输出脉冲wire key_state; //按键状态输出//例化测试模块key_filter key_filter_test(.clk(clk), //50M时钟信号.rst(rst), //低电平复位.key_in(key_in), //按键输入.key_flag(key_flag), //消抖完毕输出脉冲.key_state(key_state) //按键状态输出
);//产生100M时钟信号initial clk = 1;always #(`clk_period / 2) clk <= ~clk;//开始测试initial beginrst <= 0; //系统复位key_in <= 1; //按键处于空闲状态#(`clk_period * 2);rst <= 1;#10_000_000; //延时10ms,方便观察按键按下现象//开始模拟按键按下抖动key_in <= 0; #1000;key_in <= 1; #2000;key_in <= 0; #1400;key_in <= 1; #2600;key_in <= 0; #1300;key_in <= 1; #200;//产生一个稳定的低电平大于20ms,代表按键稳定key_in <= 0; #30_000_000;//模拟释放抖动key_in <= 1; #2000;key_in <= 0; #1000;key_in <= 1; #2600;key_in <= 0; #1400;key_in <= 1; #200;key_in <= 0; #1300;//产生一个稳定的高电平大于20ms,代表释放稳定key_in <= 1; #30_000_000;$stop;endendmodule
局部抖动
4.2. 调用task任务封装赋值并调用$random函数
- 利用$randon函数产生随机延时置模拟抖动
reg [15:0]randnum;
randnum = $random % 50; //产生一个-49~49内的随机数
randnum = {$random} % 50; //产生一个0 ~ 50内的随机数
- 利用 task / endtask 将重复代码进行封装
task <任务名>;<语句1><语句2><语句3>....
endtask
`define clk_period 20 //100M系统时钟module key_filter_2_tb();reg clk; //50M时钟信号reg rst; //低电平复位reg key_in; //按键输入wire key_flag; //消抖完毕输出脉冲wire key_state; //按键状态输出reg [15:0]rand_time; //按键抖动时随机时长//例化测试模块key_filter key_filter_test(.clk(clk), //50M时钟信号.rst(rst), //低电平复位.key_in(key_in), //按键输入.key_flag(key_flag), //消抖完毕输出脉冲.key_state(key_state) //按键状态输出
);//产生100M时钟信号initial clk = 1;always #(`clk_period / 2) clk <= ~clk;//开始测试initial beginrst <= 0; //系统复位key_in <= 1; //按键处于空闲状态#(`clk_period * 2);rst <= 1;#10_000_000; //延时10ms,方便观察按键按下现象press_key; #10000; //第一次按下按键press_key; #10000; //第二次按下按键press_key; #10000; //第三次按下按键$stop;endtask press_key;begin//开始模拟按键按下抖动repeat(50)beginrand_time = {$random} % 65536;#rand_time key_in = ~key_in; end //产生一个稳定的低电平大于20ms,代表按键稳定key_in = 0; #30_000_000;//模拟释放抖动repeat(50)beginrand_time = {$random} % 65536;#rand_time key_in = ~key_in; end//产生一个稳定的高电平大于20ms,代表释放稳定key_in = 1;#30_000_000;endendtaskendmodule
状态机按键消抖电路设计相关推荐
- 小梅哥三段式状态机按键消抖改写
小梅哥三段式状态机按键消抖改写 小梅哥资料中按键消抖部分是用一段式.二段式状态机写的.我用三段式状态机改写了一下,仿真和板载测试通过. 代码记录如下: module key_filter1(input ...
- (三) 按键消抖电路设计
由于普通物理按键存在反作用弹簧,因此当按下或者松开时均会产生额外的物理抖动,物理抖动便会产生电平的抖动.在按键从按下再到松开的过程中,其电平变化如图2.2.1所示,上为理想波形输出,下为实际波形输出. ...
- verilog基础-状态机之FPGA独立按键消抖设计与验证(熟练testbench的写法)
独立按键消抖设计与验证 本实验主要是为了锻炼状态机的思维模式以及熟练掌握TB的写法 本节主要收获了:define的用法,另外就是,顶层的input在TB中是reg的真正含义,其实就是把激励当做寄存器来 ...
- Verilog实现独立按键消抖(状态机)
本文参考小梅哥的独立按键消抖视频 1,实验原理: 这里是黑金开发板教程中的图,可以看出,按键未按下时的状态是高电平,按下为低电平.下边是小梅哥画的图解. 因为是机械按键,按下时候有一个不稳定的抖动期, ...
- 使用状态机消进行按键消抖
在机械按键内部都会有弹簧,当我们按下时会发生抖动,这可能导致我们系统对电信号的判断有误.所以可以用状态机进行消抖,我的理解就是在只要按键保持的时间没有达到一定的数值,在这个中间的抖动对归为一种状态.设 ...
- STM32按键消抖——入门状态机思维
在嵌入式软件开发中,状态机编程是一个十分重要的编程思想,它也是嵌入式开发中一个常用的编程框架.掌握了状态机编程思想,可以更加逻辑清晰的实现复杂的业务逻辑功能. 1 状态机思想 状态机,或称有限状态机F ...
- 【FPGA】状态机实现按键消抖
1.状态机简介 状态机,FSM(Finite State Machine),也称为同步有限状态机从.指的是在同步电路系统中使用的,跟随同步时钟变化的,状态数量有限的状态机,简称状态机. 状态机分类 根 ...
- STM32按键消抖的几种实现方式-STM32 Button Debouncing
一.按键抖动的现象 按键按下和松开的时候,按键金属片之间的贴合.分离有一个过程.给STM32输入的信号并不是理想的0和1切换的过程.而是如下图所示的,按下和松开的一小段时间内按键信号出现抖动(jitt ...
- 单片机按键“消抖”的思考
初学单片机时,讲到了一个按键"消抖"概念,视屏教程中只是说到要确定按键是不是真正按下,所以需要加一个延时来判断. 附上延时消抖程序代码: 代码1 void keypros() {i ...
最新文章
- Turing渲染着色器网格技术分析
- 基于深度学习的步态识别算法的MATLAB仿真
- 关于list.extend(iterable)
- 实用计算机相关日语词汇,计算机相关日语词汇整理2
- POJ - 3020 Antenna Placement(最小路径覆盖-二分图最大匹配)
- 2.9 logistic 回归中的梯度下降法
- ubuntu-18.04 设置开机启动脚本-亲测有效
- CF #439 E The Untended Antiquity
- ARM学习笔记--day10
- 单词首字母大写,将每个单词的首字母改为大写后输出
- Python字串(string)基础与20种常见操作
- CSDN博客炫丽图标调整字体大小和颜色
- SONM挖矿收益计算器
- 欧洲对撞机实现最高能级对撞 启动宇宙大爆炸实验
- PDF文件打开密码的消除办法
- 关于广州小狐科技有限公司
- IDEA连接数据库踩过的坑之无法连接到数据表
- 【笔记】白岩松:如何去看待青年人看抖音。
- python图像灰度化_python实现图片二值化及灰度处理方式
- 7-2 正负数统计 (100 分)
热门文章
- python爬去智联招聘网_Python爬虫爬取智联招聘(进阶版)
- Python Elasticsearch 报错 elasticsearch.UnsupportedProductError
- Python垃圾回收和GC模块
- 基于VUE+Echarts大屏数据展示150套 (集合)
- 新手必看的DIY装机教程(图解)
- Web端点餐系统(HTML5 + CSS3 + JS(jQuery))
- 【计算机毕业设计】家校通微信小程序的设计与实现
- 全景视频拼接(二)--OpenCV源码解析
- [转帖]ARM 相关内容
- Java、SQL Serve ----简单的增删查改