实验原理

按键做为基本的人机输入接口,在很多电子设计中都能见到,由于机械特性,在按键按下或 松开的时候,按键输入值是有抖动的,无论按下去是多平稳,都难以消除抖动,按键消抖方式有 很多,本实验主要是通过 FPGA 计时来消抖。实验中设计了一个计数器,当按键输入有变化时, 计时器清零,否则就累加,直到加到一个预定值(例如 10ms),就认为按键稳定,输出按键值, 这样就得到以后没有抖动的按键值。由于在很多地方需要用到按键下降沿或上升沿的检测,按键 消抖模块直接集成了上升沿和下降沿检测的功能。

程序设计 如下图所示,通过按键消抖后,在按键按下时,十进制计数器加 1,通过数码管译码扫描后 显示出来。

按键消抖部分的原理在上节已经讲过,按键消抖部分代码写的非常精炼,阅读起来稍显费解, 建议结合仿真波形去读代码。在提供的例程文件下的 sim 文件夹中同时提供了仿真文件,可以通 过添加仿真文件来进行仿真观察代码中信号的变化。

仿真

这里我们添加了一个串口接收的激励程序 key_debounce_tb.v 文件,用来仿真按键 key 的输入。 仿真的结果如下,我们看到按键一共有 5 次被按下,但是因为前面 4 次按键按下的低电平保持时 间都小于 20ms, 这 4 次的按下都被程序判断为抖动,只有第 5 次的按键按下时间大于了 20ms, 才 判断为按键有按下,这时 button_negedge 信号产生了一个脉冲。

module count_m10(input          clk,input          rst_n,input          en,    //Counter enableinput          clr,   //Counter synchronous reset   output reg[3:0]data,  //counter valueoutput reg     t      // carry enable signal);
always@(posedge clk or negedge rst_n)
beginif(rst_n==0)begindata <= 4'd0;t <= 1'd0;endelse if(clr)begindata <= 4'd0;t <= 1'd0;      endelse if(en)beginif(data==4'd9)begint<= 1'b1;    //Counter to 9 to generate carrydata <= 4'd0;//Counter to 9 resetendelsebegint <= 1'b0;data <= data + 4'd1;endendelset <= 1'b0;
endendmodule
`timescale 1 ns / 100 ps
module  ax_debounce
(input       clk, input       rst, input       button_in,output reg  button_posedge,output reg  button_negedge,output reg  button_out
);---------------- internal constants --------------
parameter N = 32 ;           // debounce timer bitwidth
parameter FREQ = 50;         //model clock :Mhz
parameter MAX_TIME = 20;     //ms
localparam TIMER_MAX_VAL =   MAX_TIME * 1000 * FREQ;
---------------- internal variables ---------------
reg  [N-1 : 0]  q_reg;      // timing regs
reg  [N-1 : 0]  q_next;
reg DFF1, DFF2;             // input flip-flops
wire q_add;                 // control flags
wire q_reset;
reg button_out_d0;------------------------------------------------------contenious assignment for counter control
assign q_reset = (DFF1  ^ DFF2);          // xor input flip flops to look for level chage to reset counter
assign q_add = ~(q_reg == TIMER_MAX_VAL); // add to counter when q_reg msb is equal to 0combo counter to manage q_next
always @ ( q_reset, q_add, q_reg)
begincase( {q_reset , q_add})2'b00 :q_next <= q_reg;2'b01 :q_next <= q_reg + 1;default :q_next <= { N {1'b0} };endcase
endFlip flop inputs and q_reg update
always @ ( posedge clk or posedge rst)
beginif(rst == 1'b1)beginDFF1 <= 1'b0;DFF2 <= 1'b0;q_reg <= { N {1'b0} };endelsebeginDFF1 <= button_in;DFF2 <= DFF1;q_reg <= q_next;end
endcounter control
always @ ( posedge clk or posedge rst)
beginif(rst == 1'b1)button_out <= 1'b1;else if(q_reg == TIMER_MAX_VAL)button_out <= DFF2;elsebutton_out <= button_out;
endalways @ ( posedge clk or posedge rst)
beginif(rst == 1'b1)beginbutton_out_d0 <= 1'b1;button_posedge <= 1'b0;button_negedge <= 1'b0;endelsebeginbutton_out_d0 <= button_out;button_posedge <= ~button_out_d0 & button_out;button_negedge <= button_out_d0 & ~button_out;end
end
endmodule
module key_debounce(input        clk,input        rst_n,input        key1,output [5:0] seg_sel,output [7:0] seg_data
);
wire button_negedge; //Key falling edge
ax_debounce ax_debounce_m0
(.clk             (clk),.rst             (~rst_n),.button_in       (key1),.button_posedge  ( ),.button_negedge  (button_negedge),.button_out      ()
);wire[3:0] count;
wire t0;
count_m10 count10_m0(.clk    (clk),.rst_n  (rst_n),.en     (button_negedge),.clr    (1'b0),.data   (count),.t      (t0)
);
wire[3:0] count1;
wire t1;
count_m10 count10_m1(.clk    (clk),.rst_n  (rst_n),.en     (t0),.clr    (1'b0),.data   (count1),.t      (t1)
);
//Count decoding
wire[6:0] seg_data_0;
seg_decoder seg_decoder_m0(.bin_data  (count),.seg_data  (seg_data_0)
);wire[6:0] seg_data_1;
seg_decoder seg_decoder_m1(.bin_data  (count1),.seg_data  (seg_data_1)
);
seg_scan seg_scan_m0(.clk        (clk),.rst_n      (rst_n),.seg_sel    (seg_sel),.seg_data   (seg_data),.seg_data_0 ({1'b1,7'b1111_111}),.seg_data_1 ({1'b1,7'b1111_111}),.seg_data_2 ({1'b1,7'b1111_111}),.seg_data_3 ({1'b1,7'b1111_111}),.seg_data_4 ({1'b1,seg_data_1}),.seg_data_5 ({1'b1,seg_data_0})
);
endmodule 
module seg_decoder
(input[3:0]      bin_data,     // bin data inputoutput reg[6:0] seg_data      // seven segments LED output
);always@(*)
begincase(bin_data)4'd0:seg_data <= 7'b100_0000;4'd1:seg_data <= 7'b111_1001;4'd2:seg_data <= 7'b010_0100;4'd3:seg_data <= 7'b011_0000;4'd4:seg_data <= 7'b001_1001;4'd5:seg_data <= 7'b001_0010;4'd6:seg_data <= 7'b000_0010;4'd7:seg_data <= 7'b111_1000;4'd8:seg_data <= 7'b000_0000;4'd9:seg_data <= 7'b001_0000;4'ha:seg_data <= 7'b000_1000;4'hb:seg_data <= 7'b000_0011;4'hc:seg_data <= 7'b100_0110;4'hd:seg_data <= 7'b010_0001;4'he:seg_data <= 7'b000_0110;4'hf:seg_data <= 7'b000_1110;default:seg_data <= 7'b111_1111;endcase
end
endmodule
module seg_scan(input           clk,input           rst_n,output reg[5:0] seg_sel,      //digital led chip selectoutput reg[7:0] seg_data,     //eight segment digital tube output,MSB is the decimal pointinput[7:0]      seg_data_0,input[7:0]      seg_data_1,input[7:0]      seg_data_2,input[7:0]      seg_data_3,input[7:0]      seg_data_4,input[7:0]      seg_data_5
);
parameter SCAN_FREQ = 200;     //scan frequency
parameter CLK_FREQ = 50000000; //clock frequencyparameter SCAN_COUNT = CLK_FREQ /(SCAN_FREQ * 6) - 1;reg[31:0] scan_timer;  //scan time counter
reg[3:0] scan_sel;     //Scan select counter
always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)beginscan_timer <= 32'd0;scan_sel <= 4'd0;endelse if(scan_timer >= SCAN_COUNT)beginscan_timer <= 32'd0;if(scan_sel == 4'd5)scan_sel <= 4'd0;elsescan_sel <= scan_sel + 4'd1;endelsebeginscan_timer <= scan_timer + 32'd1;end
end
always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)beginseg_sel <= 6'b111111;seg_data <= 8'hff;endelsebegincase(scan_sel)//first digital led4'd0:beginseg_sel <= 6'b11_1110;seg_data <= seg_data_0;end//second digital led4'd1:beginseg_sel <= 6'b11_1101;seg_data <= seg_data_1;end//...4'd2:beginseg_sel <= 6'b11_1011;seg_data <= seg_data_2;end4'd3:beginseg_sel <= 6'b11_0111;seg_data <= seg_data_3;end4'd4:beginseg_sel <= 6'b10_1111;seg_data <= seg_data_4;end4'd5:beginseg_sel <= 6'b01_1111;seg_data <= seg_data_5;enddefault:beginseg_sel <= 6'b11_1111;seg_data <= 8'hff;endendcaseend
endendmodule 
`timescale 1ns/1ns
module key_debounce_tb;
reg clk;
reg rst_n;
reg key1;
wire[5:0] seg_sel;
wire[7:0] seg_data;initial
beginclk = 1'b0;rst_n = 1'b0;key1 = 1'b1;#100 rst_n = 1'b1;#2000 key1 = 1'b0;#({$random} %1000)key1 = ~key1;#({$random} %1000)key1 = ~key1;#({$random} %1000)key1 = ~key1;#({$random} %1000)key1 = ~key1; #({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;    #({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = 1'b0;#1000000000key1 = 1'b1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;   #({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = 1'b1;#1000000000 key1 = 1'b0;#({$random} %1000)key1 = ~key1;#({$random} %1000)key1 = ~key1;#({$random} %1000)key1 = ~key1;#({$random} %1000)key1 = ~key1;  #({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;    #({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = 1'b0;#1000000000key1 = 1'b1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;   #({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = ~key1;#({$random} %10000000)key1 = 1'b1;#10 $stop;end
always#10 clk = ~clk;//50Mhzkey_debounce dut(.clk     (clk),.rst_n   (rst_n),.key1    (key1),.seg_sel (seg_sel),.seg_data(seg_data)
);
endmodule 

ISE 下按键消抖实验相关推荐

  1. [FPGA入门笔记](十):按键消抖实验

    简介 今天购买了AXLINX AX7020的开发板,从今天开始每一个例程都要做文档记录,为自己加油. 本实验,基于ALINX AX7020开发板,芯片为xc7z020clg400-2.开发板输入时钟为 ...

  2. 可编程逻辑器件之按键消抖实验

    一.实验目标 能够熟练的进行可编程逻辑器件开发,能够通过具体工程需求进行需求分析.模块划分.代码编写.功能仿真.综合分析.板级验证,能够独立正确的进行实验操作,培养学生的工程实践研究能力和动手实践能力 ...

  3. I.MX6U-裸机-按键消抖实验(10)

    本次实验思想是通过当按键按下之后,触发中断,如果中断时间结束后还是按下的,那么就认为确实按下了,否则认为是噪声影响. 实验步骤: 1.配置IO中断 2.初始化消抖的定时器 3.编写中断处理函数:(一个 ...

  4. 【 FPGA 】按键消抖与LED灯流动小实验

    记录一个小实验吧,实验的目的是仅仅是塞塞牙缝而已,没其他意思,很简单. 功能:拨码开关控制led灯工作与否,拨码开关为on,led灯工作,否则不工作:导航按键up和down,也就是独立按键而已,控制l ...

  5. 《按键消抖与LED控制》实验的个人思考与总结

    2019/01/08,第一个判断是否有按键按下的操作好像有问题,有空在修改! 红色为修改部分: 问题描述: 当三个独立按键的某一个被按下后,相应的LED被点亮:再次按下后,LED熄灭,按键控制LED亮 ...

  6. ARM(I.MX6ULL) EPIT定时器中断实验、定时器按键消抖

    参考:Linux之ARM (I.MX6ULL) EPIT定时器详解 作者:一只青木呀 发布时间: 2020-09-20 10:03:37 网址:https://blog.csdn.net/weixin ...

  7. ARM(IMX6U)裸机按键输入实验(BSP+SDK、GPIO输入与输出、按键消抖)

    参考:Linux之ARM(IMX6U)裸机按键输入实验(GPIO的输出与输入) 作者:一只青木呀 发布时间: 2020-08-17 21:43:37 网址:https://blog.csdn.net/ ...

  8. 关于按键消抖以及LED灯控制的一个实例

    要求: 1.未按建则所有LED全黑: 2.按K1按钮,则用前8个LED灯二进制显示25: 3.按K2按钮,则12只LED合并显示流水灯效果,3个LED点亮并向右流水. 注:是HR-240B FPGA  ...

  9. 【Verilog HDL 训练】第 09 天(按键消抖)

    5月7日 按键防抖 1. 用verilog实现按键抖动消除电路,抖动小于15ms,输入时钟12MHz. 在编写Verilog代码之前,先分析下一些前提问题,首先是几个按键(1个,多个),我们以1个和三 ...

最新文章

  1. 浅谈软件自动化集成测试的流程
  2. python processpoolexector 释放内存_关于python:如何在multiprocessing.queue中从Process中释放内存?...
  3. 数据蒋堂 | Hadoop - 一把杀鸡用的牛刀
  4. 35-03沉浸式状态栏例子
  5. letswave7中文教程1:软件安装与脑电数据导入
  6. gz格式linux怎么打开,linux 下载解压gz文件怎么打开
  7. BugkuCTF-Reverse题特殊的Base64
  8. 十年后,你在元宇宙中的一天是什么样?
  9. 二 Linux 简单配置
  10. python判断图片类型_python模块之imghdr检测图片类型
  11. layer关闭当前窗口并刷新父窗口
  12. 南大被骂到上热搜!Nature杂志回应南京大学拟花120万发校庆特刊!
  13. Revit二次开发——族的基础
  14. dhtmlx技术使用总结与介绍中文手册
  15. 三大重组股上涨最具爆发力!
  16. HDU - 1546 Idiomatic Phrases Game
  17. 魔兽世界自建服务器,魔兽世界怀旧服
  18. C#打开SDE数据库的几种方式总结
  19. Idea Rebuild project
  20. 超市收银系统测试报告

热门文章

  1. 快速游戏开发工具GameMaker Action Game Maker使用体验
  2. 饥荒为啥显示专用服务器,饥荒服务器和专用服务器有什么区别 | 手游网游页游攻略大全...
  3. 【c语言】初识c语言-让你对c语言不在感到一无所知
  4. 高铁盈利地图:东部赚翻 中西部普遍巨亏
  5. 苹果iOS越狱后没有声音的解决办法
  6. pytorch笔记:构建LSTM网络,实现训练验证和测试过程
  7. iOS开发者账号的区别
  8. strstr函数和strtok函数的使用
  9. XMPP增加删除好友
  10. 坚鹏:中国邮政储蓄银行银行业同业竞争策略分析培训圆满结束