第16章:边沿检测电路
本章对应原书第 363~366 页,属于「第四篇 数字电路篇」。
本章在讲什么?(先看这个)
信号从 0 变 1(上升沿)或从 1 变 0(下降沿)的"那一瞬间",往往是电路需要做出反应的时刻——比如按键按下的瞬间、数据就绪的瞬间。边沿检测电路的作用就是抓住这个瞬间,产生一个单时钟周期宽的指示脉冲。它是 FPGA 设计中非常经典的电路,设计思想极其重要:"打一拍,再做逻辑"——把信号延迟一拍存下来,和原信号做与/异或运算,边沿就现形了。本章一并掌握上升沿、下降沿和双沿三种检测。
核心概念拆解
边沿检测简介
边沿检测指的是检测信号的边沿,并在检测到边沿时产生相应的信号。根据检测边沿的类型,一般分为上升沿检测电路、下降沿检测电路和双沿检测电路。
在复杂的逻辑设计中,经常需要检测信号的跳变沿:如果一个信号发生跳变,逻辑就给出一个指示,用来控制其他信号的动作。边沿检测是典型的电路,其设计思想很重要——后面按键控制 LED、蜂鸣器等实验都会用到它。
上升沿检测

方法:将信号 a 延迟一拍得到 a_dly,然后用 a 和 a_dly 取反后的信号做逻辑与(a & ~a_dly),就能准确产生一个时钟周期宽度的上升沿指示脉冲 a_posedge。
原理用一句话说透:a 刚从 0 跳到 1 的那个周期,a 是 1,而 a_dly 还是上一拍的旧值 0,取反后是 1——两者相与恰好为 1,且只维持这一个周期。
下降沿检测

方法与上升沿类似,只是把 a 取反:用 ~a & a_dly,就能准确产生一个时钟周期宽度的下降沿指示脉冲 a_negedge。
a 刚从 1 跳到 0 的那个周期:a 取反为 1,a_dly 还是旧值 1,相与恰好为 1,只持续一个周期。
双沿检测

要同时检测上升沿和下降沿,方法是:将 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 视图:

图中 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 再拉低——这样既制造了一次上升沿,又制造了一次下降沿,两种边沿都能观察到。
仿真验证

从仿真波形可以看出: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 块)里,设计一个时序逻辑版本的边沿检测电路,并对比两者的波形差异。