来自正点原子的学习笔记
上一个博客是这个哦可以去看看
链接: FPGA实战(二)按键控制LED实验.
按键控制蜂鸣器实验
1 蜂鸣器简介
蜂鸣器 分有源和无源的(源:震荡源)
有源蜂鸣器自带震荡源,只需要两端加上电压就可以发出蜂鸣声(控制简单)
无源蜂鸣器不带震荡源,需要在两端加上脉冲/高低变化的脉冲信号(控制相对复杂一些)
有加号就为正极
2 硬件设计
本例程是有源的
三极管是为了增大蜂鸣器的驱动电流,电流越大声音越小。
当给BEEP的正的时候,电路导通,如图所示
3 程序设计
实验任务:使用按键控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下开关后蜂鸣器停止鸣叫,再按,重新鸣叫。
3.1 机械按键抖动
3.2 消抖
从实验目的可以看出,每次状态的变化都是通过判断上升沿/下降沿来检测的
但是由于消抖,所以说我们在第一次判断之后,延时20ms,跳过5~10ms的抖动时间,然后再判断
(从按键开始就开始处理。一律都这么处理)
还有另外一种消抖的方法是:
在抖动的过程中,按键的频率是非常高的,如果我们检测到按键的状态稳定并且超过20ms,则可以判断为抖动结束,稳定的状态。
(从按键结束开始处理)
3.3 思路 系统框图
3.4 程序设计
3.4.1 新建工程+创建源文件(基础操作)
先新建工程,
如果不会的话看看这个 Vivado 2018.3入门教程(一):创建工程+新建源文件.
3.4.2 程序编写-key_beep
module key_beep(
input clk,
input rst_n,
output key,//外部输入的按键值
output reg key_value,//消抖之后的有效值
output reg key_flag//消抖后的按键值的效标志
//指定了reg类型,下面才能赋初值
);
//reg define
reg [19:0] cnt;//定义计数器
//计数器的位宽, 系统时钟是50MHz,周期的话是20ns,要计数20ms的话每次得计数10的6次方次。
//而10的6次方用二进制表达得20位,因此采用20位宽能达够用来计算
reg key_reg;//定义寄存器,记录上一次的状态
//按键值消抖
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 20'd0;
key_reg <= 1'b1;
end
else begin
key_reg <= key;//将按键值延迟一拍
if(key_reg != key)begin //抖动状态
cnt <= 20'd100_0000;//给寄存器赋初值
//作为倒计时,看倒计时期间能否一直保持稳定
//即延时100_0000 * 20ns(1s/50MHz) = 20ms
end
else begin//如果当前按键值和前一个按键值一样,即按键没有发生变化
//开始递减,看是否稳定
if(cnt > 20'd0 )//一直递减到零
cnt <= cnt -1'b1;
else
cnt <= 20'd0;//递减到零之后,保持为零
end
end
end
//将消抖后的最终的按键值送出去
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_value <= 1'b1;
key_flag <= 1'b0;
end
//在计数器递减到1时送出按键值
else if(cnt == 20'd1) begin//稳定
//是20'd1而不是20'd0吗,因为cnt从10的6次方递减到0之后,
//else让cnt一直保持在0了,因此只能检测1的时候
//原因在于
key_value <= key;
key_flag <= 1'b1;//拉高为1
//我们想要key_flag只保持一个周期,
end
else begin//不稳定
key_value <= key_value;//依然寄存上一次的按键值,继续下一次20ms的判断
key_flag <= 1'b0;//拉低为0
end
end
endmodule
3.4.3 程序编写-beep_control
module beep_control(
input clk,
input rst_n,
//这里不需要定义key变量了
input key_value,//消抖之后的有效值
input key_flag,//消抖后的按键值的效标志
output reg beep
);
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)
beep <= 1'b1;
else if(key_flag && (key_value == 1'b0))
beep <= ~beep;
end
endmodule
3.4.4 程序编写-top_key_beep
module top_key_beep(
input clk ,
input rst_n ,
input key ,
output beep//不需要reg因为这里顶层不需要赋值了
);
//wire define
wire key_value ;
wire key_flag ;
//例化 按键消抖模块
key_beep u_key_beep(//起一个例化之后的名称
//进行模块的连接
//按住ctrl +alt键进行列操作,替换成为.
.clk (clk),
.rst_n (rst_n),
.key (key),
.key_value (key_value),//对于内部的信号,需要使用线网型的变量进行连接
.key_flag (key_flag)
);
//例化蜂鸣器控制模块
beep_control u_beep_control(
.clk (clk),
.rst_n (rst_n),
.key_value (key_value),
.key_flag (key_flag),
.beep (beep)
);
endmodule