前言
继前面的课程:按键控制led灯,本期将推出按键控制蜂鸣器发声。
一、认识蜂鸣器
蜂鸣器的发声原理由振动装置和谐振装置组成,而蜂鸣器又分为无源他激型与有源自激型。区别:有源蜂鸣器内部有震荡源,无源蜂鸣器内部没有震荡源。
二、任务描述
本实验是按键控制蜂鸣器发音。蜂鸣器的初始状态为鸣叫状态。
1.如果是鸣叫状态,按下按键后就停止鸣叫。
2.如果是停止鸣叫状态,按下按键后就重新开始鸣叫。
三、按键消抖
按键抖动:按键抖动通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。当按下一次按键,可能在A点检测到一次低电平,在B点检测到一次高电平,在C点又检测到一次低电平。同时抖动是随机,不可测的。那么按下一次按键,抖动可能会误以为按下多次按键。
- 按键消抖目的:消除按键抖动对我们程序的影响。
4. 按键消抖解决方案2:信号变化频率平稳后并且持续20ms则采样。
四、系统框图
按键控制蜂鸣器,中间通过FPGA对按键消抖,再将消抖后的按键信息输入给蜂鸣器,最后让蜂鸣器发声。
五、模块描述
一共三个模块,key_debounce用于编写按键消抖模块,beep_control用于编写控制蜂鸣器发声模块,最后使用top_key_beep调用两个模块。
六、项目代码
- 创建key_debounce文件,编写key_debounce模块代码。
module key_debounce(//按键消抖模块
input clk,
input rst_n,
input key_in,//未消抖的按键
output reg key_down//消抖过后的按键值
);
//定义按键按下四个状态
localparam IDLE = 4'b0001;
localparam FILTER_DOWN = 4'b0010;//按键按下的过程
localparam HOLD_DOWN = 4'b0100;
localparam FILTER_UP = 4'b1000;//按键松开的过程
parameter TIME_DELAY = 20'd100_0000;//消抖20ms
wire add_delay_cnt;//开始计时的标志
wire end_delay_cnt;//结束计时的标志
reg [19:0] cnt;//计数寄存器,计时20ms
reg [3:0] state_c;//现态
reg [3:0] state_n;//次态
reg key_in_r0;
reg key_in_r1;
wire n_edge;//按键按下
wire p_edge;//按键松开
//各个状态之前,相互切换到条件
wire idle2filter_down_start;//to
wire filter_down2hold_down_start;
wire filter_down2idle_start;
wire hold_down2filter_up_start;
wire filter_up2idle_start;
//接收按键信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_in_r0 <= 1'b1;
key_in_r1 <= 1'b1;
end
else begin
key_in_r0 <= key_in;
key_in_r1 <= key_in_r0;
end
end
assign n_edge = ~key_in_r0 & key_in_r1;//按键按下
assign p_edge = ~key_in_r1 & key_in_r0;//按键松开
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(*)begin
if(!rst_n)begin
state_n = IDLE;
end
else begin
case (state_c)//判断当前状态
IDLE:begin
if(idle2filter_down_start)
state_n <= FILTER_DOWN;
else
state_n <= state_c;
end
FILTER_DOWN:begin
if(filter_down2hold_down_start)begin//to
state_n <= HOLD_DOWN;
end
else if(filter_down2idle_start)begin
state_n <= IDLE;
end
else
state_n <= state_c;
end
HOLD_DOWN: begin
if(hold_down2filter_up_start)begin
state_n <= FILTER_UP;
end
else
state_n <= state_c;
end
FILTER_UP:begin
if(filter_up2idle_start)begin
state_n <= IDLE;
end
else
state_n <= state_c;
end
default: ;
endcase
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_down <= 0;
end
else if(hold_down2filter_up_start)begin
key_down <= ~key_in_r1;//如果不去反,按键按下就输出0,取反,按键按下就输出1,按键按下输出高电平,否则输出低电平
end
else begin
key_down <= 1'b0;
end
end
assign idle2filter_down_start = (state_c == IDLE) && (n_edge);
assign filter_down2idle_start = (state_c == FILTER_DOWN) &&(add_delay_cnt && p_edge);
assign filter_down2hold_down_start = (state_c == FILTER_DOWN) && (end_delay_cnt && !p_edge);
assign hold_down2filter_up_start = (state_c == HOLD_DOWN) && (p_edge);
assign filter_up2idle_start = (state_c == FILTER_UP) && (end_delay_cnt);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_delay_cnt)begin
if(end_delay_cnt)begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
else begin
cnt <= cnt;
end
end
assign add_delay_cnt = (state_c == FILTER_DOWN) || (state_c == FILTER_UP);
assign end_delay_cnt = add_delay_cnt && cnt == TIME_DELAY - 1'd1;
endmodule
- 创建beep_control文件,编写beep_ctrl模块代码。
module beep_ctrl(
input clk,
input rst_n,
input key_in,
output reg beep
);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
beep <= 1'b1;
end
else if(key_in)begin
beep <= ~beep;
end
else begin
beep <= beep;
end
end
endmodule
- 创建top_key_beep文件,编写top_key_beep模块代码。
module top_key_beep(
input clk,
input rst_n,
input key,
output beep
);
wire key_reg;//消抖完成过后的键值
key_debounce u_key_debounce(
.clk (clk),
.rst_n (rst_n),
.key_in (key),
.key_down (key_reg)
);
beep_ctrl u_beep_ctrl(
.clk (clk),
.rst_n (rst_n),
.key_in (key_reg),
.beep (beep)
);
endmodule
七、管脚信息
元件 | 管脚 |
---|---|
KEY1 | E15 |
KEY2 | E16 |
KEY3 | M16 |
KEY4 | M15 |
CLOCK(时钟) | E1 |
BUZZER(蜂鸣器) | J1 |
八、运行效果
按键控制蜂鸣器+按键消抖
总结
以上就是今天要讲的内容,本文介绍了按键控制蜂鸣器发声,由于按键存在抖动,所以通过按键抖动模块进行消抖。