一、边缘检测
1.说明
检测信号的跳变,即上升沿(0→1)或下降沿(1→0)。常用于检测1bit信号的电平跳变,例如光耦、按键、微动开关等器件在正常工作时会产生由0到1或者由1到0的跳变,检测到边沿的跳变后就能知道这些器件在什么时候被触发。
2.verilog代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 20:33:46 05/10/2024
// Design Name:
// Module Name: edge_check
// Project Name:
// Target Devices:
// Tool versions:
// Description: 这里写了一个D触发器,我们观测他的上升沿和下降沿的变化情况。
//
// Dependencies:
//
// Revision: OA
// Revision 0.01 - File Created
// Additional Comments:
//
//
module edge_check(
input wire rst_n,
input wire clk ,
input wire D ,
output wire pos_edge,
output wire neg_edge
);
reg temp0, temp1;
always @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)begin
temp0 <= 1'b0;
temp1 <= 1'b0;
end
else begin //这里敲两拍!!!!做寄存!!!
temp0 <= D;
temp1 <= temp0;
end
end
assign pos_edge = temp0 & (~temp1);
assign neg_edge = (~temp0) & temp1;
endmodule
temp0是当前值,temp1是之前值!!!
3.测试代码
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 20:43:20 05/10/2024
// Design Name: edge_check
// Module Name: D:/202405/20220213/prj/adge_check/adge_check_tb.v
// Project Name: adge_check
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: edge_check
//
// Dependencies:
//
// Revision:OA
// Revision 0.01 - File Created
// Additional Comments:
//
module adge_check_tb;
// Inputs
reg rst_n;
reg clk;
reg D;
// Outputs
wire pos_edge;
wire neg_edge;
// Instantiate the Unit Under Test (UUT)
edge_check uut (
.rst_n(rst_n),
.clk(clk),
.D(D),
.pos_edge(pos_edge),
.neg_edge(neg_edge)
);
initial begin
// Initialize Inputs
rst_n = 0;
clk = 0;
D = 0;
// Wait 100 ns for global reset to finish
#100;
rst_n = 1;
#1000;
D=1;
#5005;
D=0;
#200;
$stop;
// Add stimulus here
end
always #10 clk = ~clk;
endmodule
4.ISE仿真图
上升沿检测
下降沿检测
二、按键消抖
1.说明
按键消抖是为了防止按键信号由于机械接触不良而产生的快速开闭抖动导致的错误电信号读取,确保每次按压动作只被识别一次。通常有两种实现方式:硬件消抖和软件消抖。具体如下:
-
硬件消抖:
- 通过在按键电路中加入RC(电阻-电容)延时电路或RS触发器等硬件元件来实现。
- 硬件消抖的优点是反应速度快,因为它是在信号进入系统之前就已经完成了消抖处理。
- 缺点是需要额外的硬件支持,增加了成本和设计的复杂度。
-
软件消抖:
- 在代码中通过设置一定的延时来忽略连续的信号变化,或者使用定时器中断来过滤掉短时间内的信号抖动。
- 软件消抖的优点是不增加硬件成本,灵活性高,可以通过调整延时时间或定时器设置来适应不同的应用场景。
- 缺点是对处理器资源的占用,可能会影响其他任务的执行效率。
这里主要介绍通过延时,来进行抖动消除。
(图片搬运自ww丶121)
抖动是在按键按下与抬起时发生的,这段时间非常段,我们可以通过计数器计时20MS左右的时间之后,把稳定的信号通过flag标志,判断是否按下。
2.verilog代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 15:33:46 05/12/2024
// Design Name:
// Module Name: jitter
// Project Name:
// Target Devices:
// Tool versions:
// Description: 按键消抖
//
// Dependencies:
//
// Revision: OA
// Revision 0.01 - File Created
// Additional Comments:
//
//
module jitter(
input wire clk ,
input wire rst_n ,
input wire key , //初始为1,没按下
output reg flag //flag:1,没按下 0:按下
);
parameter t = 500_000; //计时器,t*20ns,大约10ms
reg [18:0] cnt;
reg temp0, temp1;
wire pos_edge, neg_edge;
reg [1:0] state;
always @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)begin
temp0 <= 1'b0; //初值和寄存器的输入(key)要保持一致,0的话有问题,有个毛刺,见图
temp1 <= 1'b0;
end
else begin
temp0 <= key;
temp1 <= temp0;
end
end
assign pos_edge = temp0 & (~temp1);
assign neg_edge = (~temp0) & temp1;
//计数器在下降沿的时候开始计数。
always@ (posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
flag <= 1'b1; //flag是等效替代按键的,低电平有效。
state <= 2'b00;
cnt <= 19'd0;
end
else
case(state)
2'd0 : begin
if(neg_edge) //
state <= 2'd1;
else
state <= 2'd0;
end
2'd1 : begin
if(key == 0)
begin
if(cnt == t-1)
begin
cnt <= 19'd0;
state <= 2'd2;
flag <= 1'b0;
end
else
begin
cnt <= cnt +1'b1;
state <= 2'd1;
flag <= 1'b1;
end
end
else
begin
cnt <= 19'd0;
state <= 2'd1;
flag <= 1'b1;
end
end
2'd2 : begin
if(pos_edge)
state <= 2'd3;
else
state <= 2'd2;
end
2'd3 : begin
if(key == 1)
begin
if(cnt == t-1)
begin
cnt <= 19'd0;
state <= 2'd0;
flag <= 1'b1;
end
else
begin
cnt <= cnt +1'b1;
state <= 2'd3;
flag <= 1'b0;
end
end
else
begin
cnt <= 19'd0;
state <= 2'd3;
flag <= 1'b0;
end
end
default: ;
endcase
end
endmodule
再解释一下代码,代码也就是说,通过状态机来实现,如果按下(key==0)时间超过10ms,那么判断为按下,flag拉低。以此类推。
3.测试代码
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 17:36:25 05/12/2024
// Design Name: jitter
// Module Name: D:/202405/20220213/prj/jitter/jitter_tb.v
// Project Name: jitter
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: jitter
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module jitter_tb;
// Inputs
reg clk;
reg rst_n;
reg key;
// Outputs
wire flag;
defparam jitter_inst.t = 20; //这里时间改了一下,方便测试~~~
// Instantiate the Unit Under Test (UUT)
jitter jitter_inst (
.clk(clk),
.rst_n(rst_n),
.key(key),
.flag(flag)
);
initial begin
// Initialize Inputs
clk = 0;
rst_n = 0;
key = 1;
// Wait 100 ns for global reset to finish
#100;
rst_n = 1;
#1000;
key = 0; //这里模拟抖动
#50;
key = 1;
#20;
key = 0;
#20;
key = 1;
#40;
key = 0;
#2000;
key = 1; //这里模拟抖动
#20;
key = 0;
#30;
key = 1;
#40;
key = 0;
#50;
key = 1;
#1000;
$stop;
// Add stimulus here
end
always #10 clk = ~clk;
endmodule
4.ISE仿真图
rst_n==1时,有一个毛刺,是因为初始值temp0 <= 1'b0; temp1 <= 1'b0;应该和key=1一样就没有了。