09A-独立按键消抖实验01——小梅哥FPGA设计思想与验证方法视频教程配套文档
Posted 小梅哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了09A-独立按键消抖实验01——小梅哥FPGA设计思想与验证方法视频教程配套文档相关的知识,希望对你有一定的参考价值。
芯航线——普利斯队长精心奉献
实验目的: 1.复习状态机的设计思想并以此为基础实现按键消抖
2.单bit异步信号同步化以及边沿检测
3.在激励文件中学会使用随机数发生函数$random
4.仿真模型的概念
实验平台:芯航线FPGA核心板
实验原理:
按键在电子设计中使用的最多,从复位到控制设置均可以看到其身影。现在按键的功能也种类也越来越多,例如多向按键、自锁按键、薄膜按键等。普通按键其硬件示意图如图9-1所示。
图9-1 按键示意图
芯航线开发板所载的为两脚贴片按键,分别位于开发板正面的左下角以及右下角,原理图如图9-2所示。按键不按下时IO口为高电平,按键按下时则变为电平,因此系统即可通过检测IO的电平来判断按键的状态。
图9-2 按键原理图
从图9-1中可以看到按键存在一个反作用弹簧,因此当按下或者松开时均会产生额外的物理抖动,然而物理抖动便会产生电平的抖动,总的来说,按键从按下再到松开的过程,若检测其电平变化,即如图9-4所示。
图9-4 按键从按下到松开的电平变化
图9-4中产生的抖动次数以及间隔时间均是不可预期的,这就需要滤波来消除抖动过程中可能造成的影响。一般情况抖动的总时间会持续20ms以内。这种抖动,可以通过硬件电路或者逻辑设计的方式来消除,其中硬件电路消除的电路图之一如图9-5所示。
图9-5 利用RS触发器进行硬件消抖
图9-5中两个"与非"门构成一个RS触发器。此时即使B点的电压波形是抖动的,但经双稳态电路之后,其输出为正规的矩形波。当按键未按下时,输出为1;当键按下时,输出为0。
此外还可以通过利用电容器和电阻对噪声波形积分,吸收因触点跳动产生的噪声。也可以通过555定时器组成的单稳态触发器同样可以消除开关的抖动。这两种电路此处不再详述。
对于FPGA通常使用状态机来进行消抖设计,在图9-4中可看出若按照第08讲的状态机概念对其进行状态编码即存在以下状态:未按下时空闲状态IDLE、按下抖动滤除状态FILTER0、按下稳定状态DOWN以及释放抖动滤除状态FILTER1。若对其进行独热码编码分别为0001,0010,0100以及1000。其状态转换图如图9-6所示。因此其为一个米利型状态机,输出与输入相关。
图9-6 状态转换图
其状态转移条件如表9-1所示。
当前状态 |
下一状态 |
转移条件 |
IDLE |
FILTER0 |
nedge |
FILTER0 |
IDLE |
pedge |
FILTER0 |
DOWN |
Cnt_full |
DOWN |
FILTER1 |
Pedge |
FILTER1 |
DOWN |
nedge |
FILTER1 |
IDLE |
Cnt_full |
表9-1 状态转移条件
实验步骤:
新建一个以名为key_filter的工程保存在prj下,并在本工程目录的rtl文件夹下新建verilog file文件并以key_filter.v保存。
其模块接口如图9-7所示,即可得出如下的接口声明。
图9-7 按键消抖模块接口
input Clk; input Rst_n; input key_in;
output reg key_flag; output reg key_state; |
这里的按键输入信号key_in相对于FPGA内部信号来说是一个异步信号,这里就需要对其使用两级同步D触发器进行进行异步信号的同步化,同步后的信号为key_in_sb。
reg key_in_sa,key_in_sb; always@(posedge Clk or negedge Rst_n) if(!Rst_n)begin key_in_sa <= 1\'b0; key_in_sb <= 1\'b0; end else begin key_in_sa <= key_in; key_in_sb <= key_in_sa; end |
由实验原理中的状态转移表可以看出其转换条件中需要检测到下降沿以及上升沿,而边沿检测其原理就是利用两级寄存器寄存的不同值来进行比较判断,如图9-8所示。
图9-8 边沿检测原理图
其检测过程,可以假设data_in从0变1,也就是上升沿:
第一个时钟到来第一个寄存器regc的输出为0;
第二个时钟沿到来后第一个寄存器输出为1,第二个寄存器输出此时为0,这样对两个寄存器输出进行相关组合逻辑运算则可检测出,
同理data_in从1变为0,也就是下降沿:
第一个时钟到来第一个寄存器regc的输出为1;
第二个时钟沿到来后第一个寄存器输出为0,第二个寄存器输出此时为1。
本部分逻辑设计如下,这样就实现了当有上升沿时信号pedge就会产生一个时钟周期的高电平,当有下降沿时信号nedge也会产生一个时钟周期的高电平,没有上升沿或者下降沿变化时pedge以及nedge保持低电平状态。 这里使用的"!"是逻辑非运算,对0110逻辑非运算后是0000;而"~"是按位取反,对0110按位取反后是1001。
reg key_tmpa,key_tmpb; wire pedge,nedge; always@(posedge Clk or negedge Rst_n) if(!Rst_n)begin key_tmpa <= 1\'b0; key_tmpb <= 1\'b0; end else begin key_tmpa <= key_in_sb; key_tmpb <= key_tmpa; end
assign nedge = !key_tmpa & key_tmpb; assign pedge = key_tmpa & (!key_tmpb); |
还应有20ms计数器模块以及计数器使能模块,这里也可以合并成一个always模块。一般还是推荐一个always块只对一个信号进行操作。
reg [19:0]cnt; reg en_cnt; //使能计数寄存器 //计数使能模块 always@(posedge Clk or negedge Rst_n) if(!Rst_n) cnt <= 20\'d0; else if(en_cnt) cnt <= cnt + 1\'b1; else cnt <= 20\'d0; //计数模块 always@(posedge Clk or negedge Rst_n) if(!Rst_n) cnt_full <= 1\'b0; else if(cnt == 999_999) cnt_full <= 1\'b1; else cnt_full <= 1\'b0; |
现在开始状态机设计,首先用本地参数化定义来定义其状态机。
localparam IDEL = 4\'b0001, FILTER0 = 4\'b0010, DOWN = 4\'b0100, FILTER1 = 4\'b1000; |
由于状态以及判断条件较少,此处先用一段式状态机来进行描述。当复位时候将计数器清零,状态回到IDLE,key_flag与key_state也回到初始态。
reg [3:0]state; always@(posedge Clk or negedge Rst_n) if(!Rst_n)begin en_cnt <= 1\'b0; state <= IDEL; key_flag <= 1\'b0; key_state <= 1\'b1; end else begin case(state) //。。。。。。。。 default: begin state <= IDEL; en_cnt <= 1\'b0; key_flag <= 1\'b0; key_state <= 1\'b1; end
endcase end |
在未按下时空闲状态IDLE时,如果检测到下降沿则状态进入按下抖动滤除状态FILTER0并使能计数器,否则继续保持IDLE状态。
IDEL : begin key_flag <= 1\'b0; if(nedge)begin state <= FILTER0; en_cnt <= 1\'b1; end else state <= IDEL; end |
当在FILTER0状态时,如果20ms尚未计时结束就有上升沿到来,则认为此时还是按键按下抖动过程,状态回到IDLE并清0计数器。按下过程中当最后一次抖动后不会存在上升沿,计数器则可以一直计数,计数满后则将key_flag置1、key_state置0、状态进入按下稳定状态DOWN并将计数器清0。这样就可以通过判断key_flag && !key_state来确定按键的状态,为1则按下。
FILTER0: if(cnt_full)begin key_flag <= 1\'b1; key_state <= 1\'b0; en_cnt <= 1\'b0; state <= DOWN; end else if(pedge)begin state <= IDEL; en_cnt <= 1\'b0; end else state <= FILTER0; |
进入DOWM状态后将key_flag清0,如果检测到上升沿则进入释放抖动滤除状态FILTER1,否则保持当前态。
DOWN: begin key_flag <= 1\'b0; if(pedge)begin state <= FILTER1; en_cnt <= 1\'b1; end else state <= DOWN; end |
进入FILTER1状态后,如果20ms计数尚未结束就检测到下降沿,则认为此时还是按键释放抖动过程,状态回到DOWN并清0计数器。释放过程中当最后一次抖动后不会存在下降沿,计数器则可以一直计数,计数满后则将key_flag与key_state均置1、状态进入IDLE并将计数器清0等待下一次按键被按下。
FILTER1: if(cnt_full)begin key_flag <= 1\'b1; key_state <= 1\'b1; state <= IDEL; en_cnt <= 1\'b0; end else if(nedge)begin en_cnt <= 1\'b0; state <= DOWN; 小梅哥FPGA进阶教程第九章 基于串口猎人软件的串口示波器 02-FPGA设计流程介绍——小梅哥FPGA设计思想与验证方法视频教程配套文档 06-BCD计数器设计与应用——小梅哥FPGA设计思想与验证方法视频教程配套文档 05-IP核应用之计数器——小梅哥FPGA设计思想与验证方法视频教程配套文档 |