本板子携带了一个有源蜂鸣器
有源蜂鸣器相对于无源蜂鸣器更加简单,只要加上合适的直流电压就可以发声
实验目的 :
本节实验任务是使用领航者上的 PL KEY0 按键来控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下按键后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫。
对于按键消抖 : 软件消抖的原理是当按键按下或松开后,由处理器延时5ms至20ms,然后再对按键状态进行采样判断
我们消抖的过程就是滤除按键值保持时间小于 20ms 的值,那么我们需要做的就是在按键被按下或者被释放
导致按键值产生变化时,从 20ms 开始倒计时,如果 20ms 的倒计时还没有完成按键值就再次产生变化,此
时需要从头开始 20ms 倒计时,前一次导致按键值变化的操作视为无效操作,将该次变化视为按键抖动消除;
如果计完 20ms 按键状态一直没有改变,说明此次按键被按下或者被释放是有效操作,将此次按键第二次的
打拍的值赋值给按键消抖后的信号 key_filter。
我们来讲述一下 消抖模块的工作机理和代码
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
key_d0 <= 1'b1;
key_d1 <= 1'b1;
end
else begin
key_d0 <= key;
key_d1 <= key_d0;
end
end
我们判断是否是真正的值用20ms作为一个阶段
我们用非阻塞逻辑选取了两个节点 正好是一前一后的状态 只要我们在后续上判断两数不相等 那说明两种情况
说明什么 说明要么是从0到1 要么是从1到0 我们不知道是不是毛刺从而产生跳变 所以我们就在这 此时此刻将数据设置位cnt 20ms 的值
接下来 当两个数据相等我们就开始相减
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n
cnt <= 20'd0;
else begin
if(key_d1 != key_d0) //检测到按键状态发生变化
cnt <= CNT_MAX; //则将计数器置为 20'd100_0000,
//即延时 100_0000 * 20ns(1s/50MHz) = 20ms
else begin //如果当前按键值和前一个按键值一样,即按键没有发生变化
if(cnt > 20'd0) //则计数器递减到 0
cnt <= cnt - 1'b1;
else
cnt <= 20'd0;
end
end
end
我们解析代码其中有一段 在代码相等时为什么要试探是否大于0 因为 如果不大于0 可能处于刚刚复位的阶段
这也是为什么他计算正好要到1开始跳变的原因
always @ (posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
key_filter <= 1'b1;
//在计数器递减到 1 时送出按键值
else if(cnt == 20'd1)
key_filter <= key_d1;
else
key_filter <= key_filter;
end
endmodule
在倒计时到 1 时将此时按键 key_d1 的值赋值给按键消抖后的值 key_filter。
按键消抖后的值 key_filter 为低电平表示按键被按下,按键消抖后的值 key_filter 为高电平则表示按键被释
放。
由本章硬件设计可知,我们给蜂鸣器 beep 高电平时蜂鸣器会发声鸣叫,我们给蜂鸣器低电平时蜂鸣器
停止鸣叫,初始化时我们给蜂鸣器赋值高电平;并且在按键控制 LED 实验的硬件设计我们了解过,按键没
有被按下时为高电平,按键被按下时为低电平,所以可以通过检测按键值的下降沿来判断按键是否被按下。
如果检测到按键下降沿,表示按键被按下,此时我们取反一次 beep 值,beep 值由高电平变为低电平,蜂鸣
器停止发声。等待下一次按键被按下,蜂鸣器的值再次取反,会由低电平变为高电平,蜂鸣器会再次发声,
至此实现了使用按键控制蜂鸣器发声的任务。
我们的做法就是边沿检测,当每次检查到被按下时,开始取反beep使得蜂鸣器的发声状态开始变化
assign neg_key_filter = (~key_filter) & key_filter_d0;
//对按键端口的数据延迟一个时钟周期
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
key_filter_d0 <= 1'b1;
else
key_filter_d0 <= key_filter;
end
这一段非常有深度虽然我不懂但是可以用 因为他用的是判断下降沿 那我就截取一个信号令它和上一个信号交替
然后assign x= (~0)& 1 ; 这样正好捕获下降沿
自己编写的代码
module keydebounce(
input clk,
input rst_n,
input key,
output reg out
);
// define 20ms first we use 1/50M = 20ns 20ms/20ns=100_0000
parameter CNT_MAX = 20'd100_0000; // idk y 20'd
reg[19:0] cnt;
reg key0; // one cut
reg key1; // two cut
always@(posedge clk or negedge rst_n )
begin
if(rst_n==0) begin
key0 <= 1'b1;
key1 <= 1'b1;
end
else
key0 <= key;
key1 <= key0; // we can use this contribute two state
end
// next we should contribute a build module
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 0)
cnt <= 0 ;
else begin
if(key0 != key1)
cnt <= CNT_MAX;
else begin
if(cnt > 0)
cnt <= cnt - 1;
else
cnt <= 0 ;
end
end
end
// get answer
always@( posedge clk or negedge rst_n) begin
if(rst_n == 0)
out <= 1 ;
else if(cnt == 1)
out <= key1;
else
out <= out ;
end
endmodule
下面是 beep的代码
module key_beep(
input clk,
input rst_n,
input key_filter,
output reg beep
);
// we use down to test
// first we use one state
reg key0;
wire neg_key_filter;
assign neg_key_filter = (~key_filter)&key0;
//set down
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
key0 <= 1'b1;
else
key0 <= key_filter ;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
beep <= 1;
else if(neg_key_filter)
beep <= ~beep;
else
beep <= beep;
end
endmodule