verilog学习笔记- 11)按键控制蜂鸣器实验

简介:

蜂鸣器按照驱动方式主要分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声。

                                             左边为有源蜂鸣器 右边为无源蜂鸣器

从外观上看,两种蜂鸣器很相似,如将两种蜂鸣器的引脚都朝上放置,可以看出有绿色电路板的一种是无源蜂鸣器,没有电路板而用黑胶封闭的一种是有源蜂鸣器。相较于有源蜂鸣器,无源蜂鸣器成本更低,且发声频率可控。而有源蜂鸣器控制相对简单,由于内部自带震荡源,只要加上合适的直流电压即可发声。


实验任务:

使用按键控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下开关后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫


硬件设计:

我们可以看到蜂鸣器受到三极管的控制,这里三极管充当开关的作用,它基极连接到 FPGA 的 IO 引脚当 FPGA 输出高电平时三极管导通,蜂鸣器鸣叫反之蜂鸣器停止鸣叫。

管脚分配如下表所示:

对应的 TCL 约束语句如下:

set_location_assignment PIN_E16 -to key
set_location_assignment PIN_D12 -to beep
set_location_assignment PIN_M2 -to sys_clk
set_location_assignment PIN_M1 -to sys_rst_n
set_instance_assignment -name CURRENT_STRENGTH_NEW 12MA -to beep

由于蜂鸣器需要的驱动电流较大,使用默认 8mA 的驱动电流有可能出现蜂鸣器发声较小的情况,解决方法是将蜂鸣器输出的驱动电流修改成 12mA 或者是 16mA,如下图所示: 


程序设计:

由实验任务可知,我们只需要在按键按下时改变蜂鸣器的鸣叫状态,但实际上在按键按下的过程中存在按键抖动的干扰,体现在数字电路中就是不断变化的高低电平,为避免在抖动过程中采集到错误的按键状态,我们需要对按键数据进行消除抖动处理。因此本系统应至少包含按键消抖模块和蜂鸣器控制模块,按键控制蜂鸣器系统框图如图

查看软件生成的模块端口及信号连接图。首先在对工程进行编译,然后点击菜单栏的【Tools】→【NetList Viewers】→【RTL Viewer】

需要注意的是,必须已经执行过综合或编译之后,才能打开模块端口及信号连接图。打开之后,按下键盘的【Ctrl】键,滚动鼠标的滚轮可以对生连接图进行放大和缩小。模块端口及信号连接图可以比较清晰的查看各个模块端口信号的连接,同时双击模块,也可以进一步查看模块的原理图。

顶层模块有以下两个模块,按键消抖模块(key_debounce)蜂鸣器控制模块(beep_control)。顶层模块(top_key_beep)完成了对另外两个模块的例化。按键消抖模块,主要起到延时采样,防止按键抖动的干扰。蜂鸣器控制模块,通过对按键信号的识别,起到控制蜂鸣器鸣叫的作用。

按键消抖模块(key_debounce):对按键信号延时采样,将消抖后的按键信号和按键数据有效信号输出至 beep_control 模块。蜂鸣器控制模块(beep_control):根据输入的按键信号和按键数据有效信号,来控制蜂鸣器的鸣叫。

 

按键消抖的原理。通常我们所使用的开关为机械弹性开关,当我们按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的短时间内产生机械抖动,消除这种抖动的过程即称为按键消抖。软件消抖的原理主要为按键按下或松开后延时 5ms—20ms 采样,也可以在检测到按键状态稳定后采样,即避开抖动区域后再采样,如图:

顶层模块代码如下:

1 module top_key_beep(
2 input sys_clk, //时钟信号 50Mhz
3 input sys_rst_n, //复位信号
4 
5 input key, //按键信号 
6 output beep //蜂鸣器控制信号
7 );
8 
9 //wire define
10 wire key_value;
11 wire key_flag;
12 
13 //*****************************************************
14 //** main code
15 //*****************************************************
16 
17 //例化按键消抖模块
18 key_debounce u_key_debounce(
19 .sys_clk (sys_clk),
20 .sys_rst_n (sys_rst_n),
21 
22 .key (key),
23 .key_flag (key_flag),
24 .key_value (key_value)
25 );
26 
27 //例化蜂鸣器控制模块
28 beep_control u_beep_control(
29 .sys_clk (sys_clk),
30 .sys_rst_n (sys_rst_n),
31 
32 .key_flag (key_flag), 
33 .key_value (key_value),
34 .beep (beep)
35 );
36 
37 endmodule

在顶层模块中例化了按键消抖模块和按键控制蜂鸣器模块。

按键消抖模块代码如下:

1 module key_debounce(
2 input sys_clk, //外部 50M 时钟
3 input sys_rst_n, //外部复位信号,低有效
4
5 input key, //外部按键输入
6 output reg key_flag, //按键数据有效信号
7 output reg key_value //按键消抖后的数据 
8 );
9 
10 //reg define 
11 reg [31:0] delay_cnt;
12 reg key_reg;
13 
14 //*****************************************************
15 //** main code
16 //*****************************************************
17 always @(posedge sys_clk or negedge sys_rst_n) begin
18 if (!sys_rst_n) begin
19 key_reg <= 1'b1;
20 delay_cnt <= 32'd0;
21 end
22 else begin
23 key_reg <= key;
24 if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
25 delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为 20ms)
26 else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始 20ms 倒计时
27 if(delay_cnt > 32'd0)
28 delay_cnt <= delay_cnt - 1'b1;
29 else
30 delay_cnt <= delay_cnt;
31 end 
32 end 
33 end
34 
35 always @(posedge sys_clk or negedge sys_rst_n) begin
36 if (!sys_rst_n) begin
37 key_flag <= 1'b0;
38 key_value <= 1'b1; 
39 end
40 else begin
41 if(delay_cnt == 32'd1) begin //当计数器递减到 1 时,说明按键稳定状态维持了 20ms
42 key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
43 key_value <= key; //并寄存此时按键的值
44 end
45 else begin
46 key_flag <= 1'b0;
47 key_value <= key_value;
48 end 
49 end 
50 end
51 
52 endmodule

程序中第 25 行不断检测按键状态,一旦发现按键状态发生改变,就给计数器 delay_cnt 赋初值 1000000。在按键状态不发生改变时,delay_cnt 递减从而实现倒计时的功能,在倒计时过程中,一旦检测到按键状态发生改变,则说明有抖动产生,此时重新给 delay_cnt 赋初值,并开始新一轮倒计时。在 50Mhz 时钟驱动下,delay_cnt 若能由 1000000 递减至 1,则说明按键状态保持稳定时间达 20ms,此时输出一个时钟周期的通知信号 key_flag,并将此时的按键数据寄存输出。

蜂鸣器控制模块的代码如下:

1 module beep_control(
2 //input
3 input sys_clk, //系统时钟
4 input sys_rst_n, //复位信号,低电平有效
5 
6 input key_flag, //按键有效信号
7 input key_value, //消抖后的按键信号 
8 output reg beep //蜂鸣器控制信号 
9 );
10 
11 //*****************************************************
12 //** main code
13 //*****************************************************
14 always @ (posedge sys_clk or negedge sys_rst_n) begin
15 if(!sys_rst_n)
16 beep <= 1'b1;
17 else if(key_flag && (~key_value)) //判断按键是否有效按下
18 beep <= ~beep; 
19 end
20 
21 endmodule

beep 初始状态为高电平,蜂鸣器鸣叫,当检测到按键有效信号 key_flag 为高电平,同时按键信号 key_value 为低电平时说明按键被有效按下,此时 beep 取反,蜂鸣器停止鸣叫。当按键再次按下时,beep再次取反,蜂鸣器重新开始鸣叫。

Test bench 模块代码如下:

1 `timescale 1 ns/ 1 ns
2 module tb_top_key_beep();
3 
4 //parameter define
5 parameter T = 20;
6 
7 //reg define
8 reg key;
9 reg sys_clk;
10 reg sys_rst_n;
11 reg key_value;
12 
13 // wire define 
14 wire beep;
15 
16 //*****************************************************
17 //** main code 
18 //*****************************************************
19 
20 //给信号初始值
21 initial begin
22 key <= 1'b1;
23 sys_clk <= 1'b0;
24 sys_rst_n <= 1'b0;
25 #20 sys_rst_n <= 1'b1; //在第 20ns 的时候复位信号信号拉高
26 #30 key <= 1'b0; //在第 50ns 的时候按下按键
27 #20 key <= 1'b1; //模拟抖动
28 #20 key <= 1'b0; //模拟抖动
29 #20 key <= 1'b1; //模拟抖动
30 #20 key <= 1'b0; //模拟抖动
31 #170 key <= 1'b1; //在第 300ns 的时候松开按键
32 #20 key <= 1'b0; //模拟抖动
33 #20 key <= 1'b1; //模拟抖动
34 #20 key <= 1'b0; //模拟抖动
35 #20 key <= 1'b1; //模拟抖动
36 #170 key <= 1'b0; //在第 550ns 的时候再次按下按键
37 #20 key <= 1'b1; //模拟抖动
38 #20 key <= 1'b0; //模拟抖动
39 #20 key <= 1'b1; //模拟抖动
40 #20 key <= 1'b0; //模拟抖动
41 #170 key <= 1'b1; //在第 800ns 的时候松开按键
42 #20 key <= 1'b0; //模拟抖动
43 #20 key <= 1'b1; //模拟抖动
44 #20 key <= 1'b0; //模拟抖动
45 #20 key <= 1'b1; //模拟抖动
46 end
47 
48 //50Mhz 的时钟,周期则为 1/50Mhz=20ns,所以每 10ns,电平取反一次 
49 always # (T/2) sys_clk <= ~sys_clk;
50 
51 //例化 key_beep 模块 
52 top_key_beep u1 (
53 .beep(beep),
54 .key(key),
55 .sys_clk(sys_clk),
56 .sys_rst_n(sys_rst_n)
57 ); 
58 
59 endmodule

仿真波形图如下:

测试代码中,为了方便仿真波形的查看,将按键消抖模块中的延时采样的延时时间改为四个时钟周期(将按键消抖模块中的第 26 行代码 delay_cnt <= 32'd1000000; 改为 delay_cnt <= 32'd4;)。tb_key_beep 模块中第 22 行到第 45 行为信号的激励。从图 10.4.5 可以看到,第 50ns 时,将 key 拉低,并在 50 至 130ns时模拟按键抖动,可见在按键抖动停止后的第 4 个时钟周期时,key_flag 出现一个时钟周期的高电平,同时beep 被拉低(蜂鸣器停止鸣叫);在第 300ns 时松开按键,随后模拟按键抖动,同理可知在抖动结束后的第四个时钟周期,key_flag 信号被拉高。读者可以仔细观察仿真波形结合代码深入理解,仔细体会 key_flag信号和 key 信号之间的关系。


下载验证:

功能正常 

 

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vizio<

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值