正点原子开拓者FPGA开发板上自带了一枚无源蜂鸣器,本篇将记录如何通过按键来控制蜂鸣器的开关。
功能描述
初始蜂鸣器不响,按键按一下蜂鸣器开始响,再按一下蜂鸣器停止。
模块结构
本次采用了三个模块,一个顶层模块,一个按键消抖模块和蜂鸣器控制面模块。
按键消抖
消抖,即消除抖动。 若不消除抖动,则显得过于灵敏,在短时间内会多次反复触发。 思路:每次按下给予20ms的延时,若这段时间内状态不变,则输出,否则重新计时。
模块名:key_debounce.v
代码语言:javascript复制module key_debounce(
input sys_clk, //外部50M时钟
input sys_rst_n, //外部复位信号,低有效
input key, //外部按键输入
output reg key_flag, //按键数据有效信号
output reg key_value //按键消抖后的数据
);
//reg define
reg [31:0] delay_cnt;
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 //当计数器递减到1时,说明按键稳定状态维持了20ms
key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
key_value <= key; //并寄存此时按键的值
end
else begin
key_flag <= 1'b0;
key_value <= key_value;
end
end
end
endmodule
注意:
1、计数器大小计算:20ms/20ns=10^6
2、代码第二十六行key_reg <= key;
使用非阻塞赋值,程序先将key的先前值传递给key_reg,然后将下一次的key的和之前的key进行比较,非常巧妙。
蜂鸣器控制
代码语言:javascript复制module beep_control(
//input
input sys_clk, //系统时钟
input sys_rst_n, //复位信号,低电平有效
input key_flag, //按键有效信号
input key_value, //消抖后的按键信号
output reg beep //蜂鸣器控制信号
);
//*****************************************************
//** main code
//*****************************************************
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
beep <= 1'b0;
else if(key_flag && (~key_value)) //判断按键是否有效按下
beep <= ~beep;
end
endmodule
beep为低电平(0)时,蜂鸣器不响,高电平触发鸣响。
顶层模块
代码语言:javascript复制 module top_key_beep(
input sys_clk, //时钟信号50Mhz
input sys_rst_n, //复位信号
input key, //按键信号
output beep //蜂鸣器控制信号
);
//wire define
wire key_value;
wire key_flag;
//*****************************************************
//** main code
//*****************************************************
//例化按键消抖模块
key_debounce u_key_debounce(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.key_flag (key_flag),
.key_value (key_value)
);
//例化蜂鸣器控制模块
beep_control u_beep_control(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key_flag (key_flag),
.key_value (key_value),
.beep (beep)
);
endmodule
顶层模块可以简单理解为对象实例化(面向对象的思想)