
基于FPGA的数字钟——(二)按键消抖模块设计
发布日期:2021-05-07 22:56:10
浏览次数:23
分类:精选文章
本文共 3551 字,大约阅读时间需要 11 分钟。
基于FPGA的数字钟——(二)按键消抖模块
1、硬件原理
按键按下时会有随机的抖动,因此需要在抖动期过后再进行按键状态的判断。
2、原理实现
按键引脚检测电平跳变,跳变时进行计数,计数一定时间后再判断电平·高低以判断是抖动还是真实按下。检测按键放开同理。
3、FPGA实现
设计一个状态机,有以下几个状态:IDLE(放开),FILTER0(下降沿滤波),DOWN(按下),FILTER1(上升沿滤波)。
消抖计数器计数周期为50000个时钟周期,即50000*20=1000000ns=1msverilog代码
//// 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
仿真波形图
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2025年03月28日 15时17分43秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Cassandra数据建模
2021-05-09
Elasticsearch Web管理工具
2021-05-09
Git 配置SSH公钥、私钥
2021-05-09
极客时间离线课堂
2021-05-09
Spring Session
2021-05-09
koa2 中间件里面的next到底是什么
2021-05-09
在create-react-app创建的项目下允许函数绑定运算符
2021-05-09
博客园新闻频道开始公开测试
2021-05-09
评论表聚集索引引起的评论超时问题
2021-05-09
博客园上海俱乐部4月份活动通知邀请函已经发出!
2021-05-09
上周热点回顾(5.24-5.30)
2021-05-09
Internet Explorer 10 专题上线
2021-05-09
云计算之路-阿里云上:0:25~0:40网络存储故障造成网站不能正常访问
2021-05-09
网站故障公告1:使用阿里云RDS之后一个让人欲哭无泪的下午
2021-05-09
上周热点回顾(12.31-1.6)
2021-05-09
上周热点回顾(1.21-1.27)
2021-05-09
上周热点回顾(6.3-6.9)
2021-05-09
上周热点回顾(8.12-8.18)
2021-05-09
【故障公告】升级阿里云 RDS SQL Server 实例故障经过
2021-05-09
蹒跚来迟:新版博客后台上线公测
2021-05-09