第16章:边沿检测电路

本章对应原书第 363~366 页,属于「第四篇 数字电路篇」。

本章在讲什么?(先看这个)

信号从 0 变 1(上升沿)或从 1 变 0(下降沿)的"那一瞬间",往往是电路需要做出反应的时刻——比如按键按下的瞬间、数据就绪的瞬间。边沿检测电路的作用就是抓住这个瞬间,产生一个单时钟周期宽的指示脉冲。它是 FPGA 设计中非常经典的电路,设计思想极其重要:"打一拍,再做逻辑"——把信号延迟一拍存下来,和原信号做与/异或运算,边沿就现形了。本章一并掌握上升沿、下降沿和双沿三种检测。

核心概念拆解

边沿检测简介

边沿检测指的是检测信号的边沿,并在检测到边沿时产生相应的信号。根据检测边沿的类型,一般分为上升沿检测电路下降沿检测电路双沿检测电路

在复杂的逻辑设计中,经常需要检测信号的跳变沿:如果一个信号发生跳变,逻辑就给出一个指示,用来控制其他信号的动作。边沿检测是典型的电路,其设计思想很重要——后面按键控制 LED、蜂鸣器等实验都会用到它。

上升沿检测

图16.1.1 上升沿检测电路

方法:将信号 a 延迟一拍得到 a_dly,然后用 a 和 a_dly 取反后的信号做逻辑与(a & ~a_dly,就能准确产生一个时钟周期宽度的上升沿指示脉冲 a_posedge。

原理用一句话说透:a 刚从 0 跳到 1 的那个周期,a 是 1,而 a_dly 还是上一拍的旧值 0,取反后是 1——两者相与恰好为 1,且只维持这一个周期。

下降沿检测

图16.1.2 下降沿检测电路

方法与上升沿类似,只是把 a 取反:~a & a_dly,就能准确产生一个时钟周期宽度的下降沿指示脉冲 a_negedge。

a 刚从 1 跳到 0 的那个周期:a 取反为 1,a_dly 还是旧值 1,相与恰好为 1,只持续一个周期。

双沿检测

图16.1.3 双沿检测电路

要同时检测上升沿和下降沿,方法是:将 a 延迟一拍得到 a_dly,然后把 a 与 a_dly 做异或(a ^ a_dly。当 a 发生跳变(无论上升还是下降)时,两者必然一个为 0 一个为 1,异或输出 1,产生一个单时钟周期的高电平脉冲 a_edge。

三种检测放在一起记:

检测类型 表达式 说明
上升沿 a & ~a_dly 现在是1,上一拍是0
下降沿 ~a & a_dly 现在是0,上一拍是1
双沿 a ^ a_dly 现在和上一拍不同

实验任务

使用 Verilog 语言设计上升沿、下降沿和双沿检测电路。

程序设计——编写代码

module edge_test(
    input            sys_clk     ,//系统时钟
    input            sys_rst_n   ,//系统复位
    input            a           ,//输入信号

    output           a_posedge   ,//输出上升沿
    output           a_negedge   ,//输出下降沿
    output           a_edge       //输出双沿
    );

//*****************************************************
//**                    main code
//*****************************************************

//define reg
reg      a_dly;    //a延迟一拍后的信号

//对a打拍获得a_dly
always@(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        a_dly <= 1'b0;
    else
        a_dly <= a;
end

assign a_posedge = a & ~a_dly;    //取上升沿
assign a_negedge = ~a & a_dly;    //取下降沿
assign a_edge    = a ^ a_dly ;    //取双沿

endmodule

代码结构非常清晰,分两部分:

  • 打拍(第 19~24 行):时序逻辑把输入 a 延迟一拍存入 a_dly;
  • 组合逻辑(第 26~28 行):三条 assign 分别完成上升沿、下降沿、双沿的提取。

用 Vivado 的 RTL ANALYSIS 查看 RTL 视图:

图16.3.1 边沿检测电路RTL视图

图中 a_dly 是 a 寄存一拍的结果;a_posedge 是上升沿检测输出;a_negedge 是下降沿检测输出;a_edge 是双沿检测输出(异或门)。一拍延迟的寄存器加上几个门电路,就是边沿检测的全部硬件成本。

仿真验证——编写 TB 文件

只需对输入信号 a、时钟和复位加激励:

`timescale 1ns / 1ns //仿真单位/仿真精度

module tb_edge_test();

//define reg
reg          sys_clk     ; //系统时钟
reg          sys_rst_n   ; //系统复位
reg          a           ; //输入信号

//define wire
wire         a_posedge   ; //输出上升沿
wire         a_negedge   ; //输出下降沿
wire         a_edge      ; //输出双沿

//信号初始化
initial begin
    sys_clk = 1'b1;
    sys_rst_n <= 1'b0;
    a <= 1'b0;
    #201
    sys_rst_n <= 1'b1;
    #20
    a <= 1'b1;
    #100
    a <= 1'b0;
end

//生成50MHz系统时钟
always #10 sys_clk <= ~sys_clk;

//例化边沿检测模块
edge_test    edge_test_inst(
    .sys_clk     (sys_clk    ),
    .sys_rst_n   (sys_rst_n  ),
    .a           (a          ),

    .a_posedge   (a_posedge  ),
    .a_negedge   (a_negedge  ),
    .a_edge      (a_edge     )
);

endmodule

激励设计:先复位 201ns 后释放;a 拉高 100ns 再拉低——这样既制造了一次上升沿,又制造了一次下降沿,两种边沿都能观察到。

仿真验证

图16.3.2 边沿检测模块仿真波形

从仿真波形可以看出:a 上升的那个时钟周期,a_posedge 出现单周期高脉冲;a 下降的那个时钟周期,a_negedge 出现单周期高脉冲;a_edge 则在两个跳变处各出现一个单周期脉冲。三路输出都与理论波形一致。

本章总结

本章讲解了几种常用边沿检测电路——上升沿、下降沿、双沿检测,并通过波形图详解了原理,最后完成了 edge_test 模块的设计与仿真。核心套路就是"打一拍 + 组合逻辑":a & ~a_dly 取上升沿、~a & a_dly 取下降沿、a ^ a_dly 取双沿。后续章节(按键控制 LED 等)会经常与边沿检测打交道,务必熟记这三条表达式。

图片对照

本章图片已按讲解位置分散插入各小节,包括三种边沿检测的波形图、RTL 视图和仿真波形。

初学者容易踩的坑

  • 两条表达式写反a & ~a_dly~a & a_dly 一字之差就是上升沿和下降沿的区别,写反了现象恰好颠倒。
  • 忘记打拍或打错对象:a_dly 必须是 a 的延迟版本;如果忘了打拍直接 a & ~a 恒为 0,什么也检测不到。
  • 误以为脉冲会持续:检测输出只维持一个时钟周期,如果后续模块时钟不同或处理较慢,可能"错过"这个脉冲——必要时需要展宽或握手。
  • 检测异步信号不加同步:如果被检测的 a 来自外部(如按键),严格来说应先做两级同步再打拍检测,否则可能出现亚稳态(本章为纯逻辑演示,实际工程中要注意)。
  • 复位值遗漏:a_dly 复位时记得清零,否则仿真一开始 a_dly 是不定态,三路输出全乱。

小结 & 下一步

本章掌握了 FPGA 设计中最经典的"打一拍"边沿检测套路,三条核心表达式务必背下来。建议动手拓展:本章用的是组合逻辑输出(assign)实现边沿检测,试着把检测结果也放进时序逻辑(带时钟的 always 块)里,设计一个时序逻辑版本的边沿检测电路,并对比两者的波形差异。