目录
按键控制蜂鸣器实验
1、简介
2、实验任务
3、程序设计
3.1、顶层模块代码
3.2、按键消抖模块代码
3.3、蜂鸣器控制模块代码
4、仿真验证
5、板上下载验证
5.1、硬件设计
5.2、添加约束文件.xdc
5.3、板上下载验证
按键控制蜂鸣器实验
蜂鸣器(Buzzer)是现代常用的一种电子发声器,主要用于产生声音信号。蜂鸣器在生活中已经得到广泛使用,其典型应用包括医疗,消防等领域的各种报警装置以及日常生活中的各种警报器等。本章我们主要学习如何使用按键来控制蜂鸣器发声。
1、简介
蜂鸣器按照驱动方式主要分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一 般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声。
如图 10.1.1 所示,从外观上看,两种蜂鸣器很相似,如将两种蜂鸣器的引脚都朝上放置,可以看出有绿色电路板的是无源蜂鸣器,没有电路板而用黑胶封闭的是有源蜂鸣器。
相较于有源蜂鸣器,无源蜂鸣器成本更低,且发声频率可控。而有源蜂鸣器控制相对简单,由于内部自带震荡源,只要加上合适的直流电压即可发声。本次实验使用的蜂鸣器为图 10.1.2 中的有源蜂鸣器。
2、实验任务
本节实验任务是使用按键控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下 key0 按键后蜂鸣器停止鸣叫,再次按下 key0 按键,蜂鸣器重新鸣叫。
3、程序设计
由实验任务可知,我们只需要在按键按下时改变蜂鸣器的鸣叫状态,但实际上在按键按下的过程中存在按键抖动的干扰,体现在数字电路中就是不断变化的高低电平,为避免在抖动过程中采集到错误的按键状态,我们需要对按键数据进行消除抖动处理。因此本系统应至少包含按键消抖模块和蜂鸣器控制模块,按键控制蜂鸣器系统框图如图 10.4.1 所示。
这里我们补充下如何查看软件生成的模块端口及信号连接图。首先在对工程进行编译,然后点击菜单栏的 Open Elaborated Design→Yes ,之后弹出的对话框选择 OK,如图 10.4.2 所示:
稍后就可以看到软件生成的模块端口及信号连接图了,如下图 10.4.3 所示:
打开之后,按下键盘的【Ctrl】键,滚动鼠标的滚轮可以对生连接图进行放大和缩小。模块端口及信号连接图可以比较清晰的查看各个模块端口信号的连接,同时双击模块,也可以进一步查看模块的原理图。
由图 10.4.3 的连接图可知,顶层模块例化了以下两个模块,按键消抖模块(key_debounce)和蜂鸣器控制模块(beep_control)。顶层模块(top_key_beep)完成了对另外两个模块的例化。按键消抖模块,主要起到延时采样,防止按键抖动的干扰。蜂鸣器控制模块,通过对按键信号的识别,起到控制蜂鸣器鸣叫的作用。
- 按键消抖模块(key_debounce):对按键信号延时采样,将消抖后的按键信号和按键数据有效信号输出至 beep_control 模块。
- 蜂鸣器控制模块(beep_control):根据输入的按键信号和按键数据有效信号,来控制蜂鸣器的鸣叫。
在这里我们介绍按键消抖的原理。通常我们所使用的开关为机械弹性开关,当我们按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的短时间内产生机械抖动,消除这种抖动的过程即称为按键消抖。
按键消抖可分为硬件消抖和软件消抖。硬件消抖主要使用 RS 触发器或电容等方法实现消抖,一般在按键较少时使用。软件消抖的原理主要为按键按下或松开后延时 5ms—20ms 采样,也可以在检测到按键状态稳定后采样,即避开抖动区域后再采样,如图 10.4.4 所示。
3.1、顶层模块代码
顶层模块代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/11 14:03:56
// Design Name:
// Module Name: top_key_beep
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//实验任务
//本节实验任务是使用按键控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,
//按下 key0 按键后蜂鸣器停止鸣叫,再次按下 key0 按键,蜂鸣器重新鸣叫。
//顶层模块代码
module top_key_beep(
input sys_clk, //时钟信号50MHz <---达芬奇Pro FPGA
input sys_rst_n, //reset ,low active //系统复位,低电平有效
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
在顶层模块中例化了按键消抖模块和按键控制蜂鸣器模块。
3.2、按键消抖模块代码
按键消抖模块代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/11 17:03:40
// Design Name:
// Module Name: key_debounce
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//按键消抖模块
module key_debounce(
input sys_clk, //50MHz时钟
input sys_rst_n, //复位信号,低频有效
input key, //外部按键输入
output reg key_flag, //按键数据有效信号
output reg key_value //按键消抖后的数据
);
//reg define
reg [31:0] delay_cnt;
reg key_reg;
//(系统时钟50MHz,一个时钟周期是1/50MHz=0.02us=20ns)(0.2s需计数:0.2s/20ns=10_000_000次)
//(系统时钟200MHz,一个时钟周期是1/200MHz=0.005us=5ns)(20ms需计数:20ms/5ns=4_000_000次)
//*************************************************************
//** 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) begin //一旦检测到按键状态发生变化(有按键按下或者释放)
//delay_cnt <= 32'd1000_000;//给延时计数器重新装载初始值(计数时间为20ms)
delay_cnt <= 32'd4; //仅用于仿真
end
else begin //按键状态稳定时,计数器递减,开始20ms倒计时
if (delay_cnt >32'd0)
delay_cnt <= delay_cnt - 1'b1;
else
delay_cnt <= 32'd0;
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 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
endmodule
程序中第 50 行不断检测按键状态,一旦发现按键状态发生改变,就给计数器 delay_cnt 赋初值 1000000。 在按键状态不发生改变时,delay_cnt 递减从而实现倒计时的功能,在倒计时过程中,一旦检测到按键状态发生改变,则说明有抖动产生,此时重新给 delay_cnt 赋初值,并开始新一轮倒计时。在 50Mhz 时钟驱动下,delay_cnt 若能由 1000000 递减至 1,则说明按键状态保持稳定时间达 20ms,此时输出一个时钟周期的通知信号 key_flag,并将此时的按键数据寄存输出。代码第 51 行 delay_cnt 赋值为 200,这仿真时的延迟数据。
3.3、蜂鸣器控制模块代码
蜂鸣器控制模块的代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/11 17:02:56
// Design Name:
// Module Name: beep_control
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//蜂鸣器控制模块
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'b1;
else if( key_flag && (~key_value) ) //判断按键是否按下有效
beep <= ~beep;
end
endmodule
beep 初始状态为高电平,蜂鸣器鸣叫,当检测到按键有效信号 key_flay 为高电平,同时按键信号key_value 为低电平时说明按键被有效按下,此时 beep 取反,蜂鸣器停止鸣叫。当按键再次按下时,beep 再次取反,蜂鸣器重新开始鸣叫。
4、仿真验证
为了验证我们的程序,我们在 Vivado 内对代码进行仿真。
Test bench 模块代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/11 15:52:20
// Design Name:
// Module Name: tb_top_key_beep
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//Test bench模块
module tb_top_key_beep();
//parameter define
parameter T = 20; //达芬奇Pro 系统时钟50MHz
//parameter T = 5; //200MHz系统时钟 <---黑金 ARTIX7-xc7a35t 没有蜂鸣器
//reg define
reg key;
reg sys_clk;
reg sys_rst_n;
reg key_value;
//wire define
wire beep;
//***********************************************************
//** main code
//***********************************************************
//给信号初始值
initial begin
key <= 1'b1;
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
#20 sys_rst_n <= 1'b1; //在第20ns的时候复位信号拉高
#30 key <= 1'b0; //在第50ns的时候按下按键
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#170 key <= 1'b1; //在第300ns的时候松开按键
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#170 key <= 1'b0; //在第550ns的时候再次按下按键
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#170 key <= 1'b1; //在第800ns的时候松开按键
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0;
end
//50MHz的时钟,周期则为1/50MHz=20ns,所以每10ns,电平取反一次
always #(T/2) sys_clk <= ~sys_clk;
//always #(T/2) sys_clk_p <= ~sys_clk_p;
//assign sys_clk_n=~sys_clk_p;
//实例化key_beep模块
top_key_beep u_top_key_beep(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.beep (beep)
);
endmodule
仿真波形图如下:
测试代码中,为了方便仿真波形的查看,将按键消抖模块中的延时采样的延时时间改为 4 个时钟周期(将按键消抖模块中的第 47 行代码 delay_cnt <= 32'd1000000; 改为 delay_cnt <= 32'd4;)。tb_key_beep 模块中第 44 行到第 68 行为信号的激励。从图 10.4.5 可以看到,第 50ns 时,将 key 拉低,并在 50 至 130ns 时模拟按键抖动,可见在按键抖动停止后的第 4 个时钟周期时,key_flag 出现一个时钟周期的高电平,同时 beep 被拉低(蜂鸣器停止鸣叫);在第 300ns 时松开按键,随后模拟按键抖动,同理可知在抖动结束后的第四个时钟周期,key_flag 信号被拉高。读者可以仔细观察仿真波形结合代码深入理解,仔细体会 key_flag 信号和 key 信号之间的关系。
5、板上下载验证
5.1、硬件设计
本实验的管脚分配如下表所示:
5.2、添加约束文件.xdc
############### clock define 时钟引脚、电平信号约束#######################
set_property -dict {PACKAGE_PIN R4 IOSTANDARD LVCMOS15} [get_ports sys_clk]
############### reset key define##########################
set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS15} [get_ports sys_rst_n]
############### key define ############################
set_property -dict {PACKAGE_PIN T4 IOSTANDARD LVCMOS15} [get_ports key]
set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS15} [get_ports beep]
5.3、板上下载验证
编译工程并生成比特流.bit 文件后,接下来我们下载比特流.bit 文件,验证按键控制蜂鸣器的功能。程序下载完成后,蜂鸣器会发出名叫,按下 KEY0 蜂鸣器停止鸣叫,再按下 KEY0 蜂鸣器再次鸣叫。如下图所示: