FPGA学习系列
前段时间,学校事情太多,还有忙着比赛,没有更新,现在也在准备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就认为是有效的,如果有抖动,就会一直重新计数,以此达到了消抖的效果。文章来源:https://www.toymoban.com/news/detail-410141.html
后续,我会把之前的工程,仿真等文件慢慢补上。
之后将同步更新PYNQ系列。文章来源地址https://www.toymoban.com/news/detail-410141.html
到了这里,关于FPGA学习—按键控制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!