推荐答案
测试一下
题目
用Verilog实现按键抖动消除电路,输入时钟频率为50Mhz,按键信号a低于设定宽度(由cnt_cfg配置:00b表示5ms,01b表示10ms,10b表示15ms,11b表示20ms)时,表示该信号是抖动,需要消除。
参考答案与知识点
参考答案
设计思路:按键消抖电路需检测输入信号a的边沿变化,当a稳定超过设定时间后输出才跟随。首先对异步输入a进行两级同步(使用两个D触发器)以消除亚稳态。然后通过边沿检测电路捕捉a的上升沿和下降沿。计数器根据同步后的信号稳定电平开始计数,计数阈值由cnt_cfg配置(00:5ms对应250000;01:10ms对应500000;10:15ms对应750000;11:20ms对应1000000)。当同步信号发生变化时计数器清零并重新开始计;若计数器计满阈值,则判定信号稳定,输出b更新为当前同步信号电平。核心代码如下:
```verilog
module debounce(
input clk, // 50MHz
input rst_n,
input [1:0] cnt_cfg,
input a, // 异步按键输入
output reg b // 消抖后输出
);
reg [1:0] sync_a; // 两级同步
reg [19:0] cnt; // 20位计数器(最大1000000)
reg [19:0] max_cnt; // 阈值
reg a_prev; // 用于边沿检测
// 同步器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) sync_a <= 2'b0;
else sync_a <= {sync_a[0], a};
end
// 阈值选择
always @(*) begin
case(cnt_cfg)
2'b00: max_cnt = 20'd250000 - 1;
2'b01: max_cnt = 20'd500000 - 1;
2'b10: max_cnt = 20'd750000 - 1;
2'b11: max_cnt = 20'd1000000 - 1;
default: max_cnt = 20'd250000 - 1;
endcase
end
// 边沿检测与计数
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 20'b0;
a_prev <= 1'b0;
b <= 1'b0;
end else begin
a_prev <= sync_a[1];
// 检测到边沿(电平变化)则计数器置0
if (sync_a[1] != a_prev) begin
cnt <= 20'b0;
end else if (cnt < max_cnt) begin
cnt <= cnt + 1'b1;
end
// 计数器满表示稳定,更新输出
if (cnt == max_cnt) begin
b <= sync_a[1];
end
end
end
endmodule
```
注意:阈值减1是因为计数器从0开始;若使用边沿触发清零,则最后一次计数完成后输出更新;可在计数满后保持输出直到下次边沿。易错点:阈值计算错误(5ms/20ns=250000),忘记同步异步输入,以及边沿检测时使用组合逻辑或时序逻辑不当。
涉及知识点
- Verilog
- 时钟
- verilog