「BUAA-CO」P1_Verilog边沿检测总结


上升沿(或下降沿)检测

如图所示,当检测到上升沿时,out会变为高电平,同时维持一个周期,然后变为低电平等待下一次检测。
上升沿识别
只需要设定一个临时reg类型变量来储存上一次的in值,然后在下一上升沿进行识别即可,代码如下

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    reg [7:0] temp;

    always @ (posedge clk)
        begin
            temp <= in; //temp始终比in晚一个周期
            pedge <= ~temp & in; //当输出为1时检测到上升沿
            //本题刚好与所示时序图相反,其中Q就相当于temp, D就相当于in,检测下降沿是对in取反就好。
        end
endmodule

上升沿和下降沿同时检测

时序图如下

该问题比较简单,只需要稍微修改以下计算out的表达式即可

reg [7:0] in_temp;
always @ (posedge clk)
    begin
        in_temp <= in;
        anyedge <= in ^ in_temp;
    end
end

下降沿(或上升沿)捕获

捕获的意思是,只要检测到下降沿,就使得输出信号out一直保持高电平,直至复位信号reset值为1(此处为同步复位)。时序图如下——

此时我们需要注意,“使out在复位之前一直保持值为1”的方法。

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output reg [31:0] out
);
    reg [31:0] in_temp;

    always @(posedge clk) begin
        in_temp <= in;
        if(reset) out <= 0;
        else begin
            out <= (in_temp & ~in) | out;
        end
    end 
endmodule

双边沿检测触发器

此时我们要构造一个触发器使其可以同时检测时钟的上升沿和下降沿,时序图如下——

由于always中的敏感列表不支持(posedge clk or negedge clk),因此我们可以使用两个always语句然后结合MUX实现

module top_module (
    input clk,
    input d,
    output q
);
    reg a, b;
    assign q = (clk) ? a : b;

    always @(posedge clk) begin
        a <= d;
    end
    always @(negedge clk) begin
        b <= d;
    end
endmodule

还有以下使用XOR的方法解决,可以说是非常巧妙了。
module top_module(
    input clk,
    input d,
    output q);

    reg p, n;

    // clk的上升沿
    always @(posedge clk)
        p <= d ^ n;

    // clk的下降沿
    always @(negedge clk)
        n <= d ^ p;

    //在上升沿时候,p=d^n, 则q=d^n^n=d;
    //在下降沿时候,n=d^p, 则q=p^d^p=d;
    //加载一个新值时会取消旧值。
    assign q = p ^ n;


    // 这样写是无法综合的
    /*always @(posedge clk, negedge clk) begin
        q <= d;
    end*/


endmodule


文章作者: Hyggge
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hyggge !
  目录