赞
踩
前段时间,学校事情太多,还有忙着比赛,没有更新,现在也在准备fpga创新设计大赛,有空就继续更新。
我使用的是vivado,在编程部分应该就IP核的创建和quartusii不一样,模块代码是可以通用的。后面也会放出工程链接,也会有quartusii和vivado的工程。附带modelsim的仿真文件。
首先,如果之前学过51、stm32等其他各类单片机,应该会知道按键消抖这个概念。我也在说明一遍,这里引用正点原子加上我个人的理解。
按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。
类似51或者stm32,常见就是利用delay,又或者用定时器实时扫描。对于fpga,我觉得其消抖方式和定时器很类似。首先,定义一个计数器,当有按键按下,计数器不断自增,若因为抖动,则计数器会清空,重新计数,当不抖动的时候,就会计满,此时才会判定为按键按下,从而实现了消抖。
代码如下(此处用递减,效果是一样的 把值改成1000000-1即可 因为从0开始加)
//计数消除抖动 类似定时器 module key_filter( input wire sys_clk, //50M时钟 input wire sys_rst_n, //复位信号,低电平有效 input wire key, //按键输入(此处一个按键) output reg key_flag, //按键数据有效信号(方便输出去控制) output reg key_value //按键消抖后的数据 ); //reg reg [31:0] delay_cnt; //32位定时器 reg key_reg; //***************************************************** //** main code //***************************************************** always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin key_reg <= 1'b1; delay_cnt <= 32'd0; end else begin key_reg <= key; if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放) delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为20ms) else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始20ms倒计时 if(delay_cnt > 32'd0) //不稳定的话,值就会重新递减 以此起到消抖 delay_cnt <= delay_cnt - 1'b1; else delay_cnt <= delay_cnt; end end end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin //一开始复位 按键按下为低电平,所以复位时按键值为高电平 key_flag <= 1'b0; key_value <= 1'b1; end else begin if(delay_cnt == 32'd1) begin //当计数器递减(改为加法也行加到1000000-1)到1时,说明按键稳定状态维持了20ms key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号 key_value <= key; //并寄存此时按键的值 end else begin key_flag <= 1'b0; key_value <= key_value; end end end endmodule
已经有了按键消抖,那么只要把该模块的key_value和key_flag输出即可,然后对key_value和key_flag进行判断,然后就可以实现相应的控制了。
控制部分的模块 控制蜂鸣器和灯
module key_control( input wire sys_clk, //系统时钟 input wire sys_rst_n, //复位信号,低电平有效 input wire key_flag, //按键有效信号 input wire key_value, //消抖后的按键信号 output reg beep, //蜂鸣器控制信号 output reg led //灯控制 ); //控制部分 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin led <= 1'b0; beep <= 1'b0; end else if(key_flag && (~key_value)) //判断按键是否有效按下 begin //按键有效是低电平,所以取反 beep <= ~beep; //再加上按键有效标志约束,更稳定 led <= 1'b1; end end endmodule
例化上述两个模块
//顶层模块 module top_key ( input wire sys_clk , //时钟信号50Mhz input wire sys_rst_n , //复位信号 input wire key , //按键信号 output wire beep , //蜂鸣器控制信号 output wire led //灯控制信号 ); //wire wire key_value; wire key_flag; //例化 //按键消抖模块 key_filter key_filter_inst ( .sys_clk (sys_clk ) , //50M时钟 .sys_rst_n (sys_rst_n ) , //复位信号,低电平有效 .key (key ) , //按键输入(此处一个按键) .key_flag (key_flag) , //按键数据有效信号(方便输出去控制) .key_value (key_value) //按键消抖后的数据 ); //按键控制模块 key_control key_control_inst ( .sys_clk (sys_clk) , //50M时钟 .sys_rst_n (sys_rst_n) , //复位信号,低电平有效 .key_flag (key_flag) , //按键有效信号 .key_value (key_value) , //消抖后的按键信号 .beep (beep) , //蜂鸣器控制信号 .led (led) //灯控制 ); endmodule
主要通过定义一个计数器,按键有效时开始计数,如果计数了20ms就认为是有效的,如果有抖动,就会一直重新计数,以此达到了消抖的效果。
后续,我会把之前的工程,仿真等文件慢慢补上。
之后将同步更新PYNQ系列。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。