数字电路专题:边沿检测(上升沿 、下降沿,双边沿)

边沿检测

1、上升沿检测
代码如下:

module signal_pos(
                  input i_clk,    //时钟输入
                  input i_rst_n,   //复位信号
                  input i_signal,  //  输入信号   待检测信号
                
                  output  pos_pulse  //输出脉冲信号
                  );
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)
begin
   if(!i_rst_n)begin
      signal_reg0 <= 1'b0;
      signal_reg0 <= 1'b0;  
   end
   else
   begin
      signal_reg0 <= i_signal;
      signal_reg1 <= signal_reg0 ; 
   end
end
assign pos_pulse  = ~signal_reg1  &  signal_reg0   //上升沿脉冲  宽度:一个时钟周期
endmodule 

时序分析如下:
D 为输入原始信号:i_signal
在这里插入图片描述

2、下降沿检测
代码如下:

module signal_neg(
                  input i_clk,    //时钟输入
                  input i_rst_n,   //复位信号
                  input i_signal,  //  输入信号   待检测信号
                
                  output  neg_pulse  //输出脉冲信号
                  );
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)
begin
   if(!i_rst_n)begin
      signal_reg0 <= 1'b0;
      signal_reg0 <= 1'b0;  
   end
   else
   begin
      signal_reg0 <= i_signal;
      signal_reg1 <= signal_reg0 ; 
   end
end
assign neg_pulse  = signal_reg1  &  (~signal_reg0)   //下降沿脉冲  宽度:一个时钟周期
endmodule 

时序分析如下:
D 为输入原始信号:i_signal
在这里插入图片描述
3、双边沿检测
代码如下:

module signal_neg_pos(
                  input i_clk,    //时钟输入
                  input i_rst_n,   //复位信号
                  input i_signal,  //  输入信号   待检测信号
                
                  output  neg_pos_pulse  //输出脉冲信号
                  );
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)
begin
   if(!i_rst_n)begin
      signal_reg0 <= 1'b0;
      signal_reg0 <= 1'b0;  
   end
   else
   begin
      signal_reg0 <= i_signal;
      signal_reg1 <= signal_reg0 ; 
   end
end
assign neg_pos_pulse  = signal_reg1  ^  signal_reg0   //上升沿、下降沿脉冲  宽度:一个时钟周期
endmodule 

时序分析如下:
D 为输入原始信号:i_signal
在这里插入图片描述

边沿检测还可以这么写

这里有给出了一种检测边沿的方法,代码大同小异。

module signal_neg_pos(
                  input i_clk,    //时钟输入
                  input i_rst_n,   //复位信号
                  input i_signal,  //  输入信号   待检测信号
                
                  output  negedge_pulse,  //检测下降沿 输出脉冲信号
                  output  posedge_pulse,  //检测上升沿 输出脉冲信号
                  output  both_edge_pulse  //检测双边沿 输出脉冲信号
                  ); 
reg [1:0]signal_edge;
always @(posedge clk)
begin
   if(!i_rst_n)begin
      
      signal_edge <= 2'b0;  
   end
   else
   begin
     signal_edge <= {signal_edge[0],i_signal}  //输入信号从低位进入,左移,bit1为旧状态,bit0 为新状态
   end
end
//双边沿沿:旧状态bit1 与 新状态bit0  异或需为1,故需 signal_edge[0]  ^  signal_edge[1]  == 1
//上升沿:旧状态bit1应为 0,新状态bit0应为 1,故需 signal_edge[1:0] == 2‘b01
//下降沿:旧状态bit1应为 1,新状态bit0应为 0,故需 signal_edge[1:0] == 2‘b10

assign both_edge_pulse  = signal_edge[0]  ^  signal_edge[1]  //双边沿    宽度:一个时钟周期
assign posedge_pulse  = (signal_edge[1:0] == 2'b01) ; //上升沿  宽度:一个时钟周期
assign negedge_pulse  = (signal_edge[1:0] == 2'b10) ;  //下降沿  宽度:一个时钟周期

//类似前一种方案,还可以这样写
//assign both_edge_pulse  = signal_edge[0]  ^  signal_edge[1]  //双边沿    宽度:一个时钟周期
//assign posedge_pulse  = ~signal_edge[1] & signal_edge[0] ; //上升沿  宽度:一个时钟周期
//assign negedge_pulse  = signal_edge[1] &  ~signal_edge[0] ;  //下降沿 宽度:一个时钟周期
endmodule 

亚稳态解决

避免亚稳态,只需要将输入信号打几拍即可
方案1:
跟上面边沿检测一个思路

module signal_buff_out(
                  input i_clk,    //时钟输入
                  input i_rst_n,   //复位信号
                  input i_signal,  //  输入信号   待检测信号
                
                  output  out_buff  // 打拍缓冲输出信号
                 
                  ); 
          
reg [15:0] signal_reg;
reg [3:0] bit_num;
always @(posedge clk)
begin
   if(!i_rst_n)begin
      
      signal_reg <= 16'b0;  
   end
   else
   begin
     signal_edge <= {signal_reg[14:0],i_signal}  
   end
end
assign  out_buff   =  signal_edge[bit_num];  //根据需要,选择输入信号打拍次数 :0-15 ,0:打一拍
endmodule 

方案2:
这种方法使用打拍次数较少的场合

module signal_buff_out(
                  input i_clk,    //时钟输入
                  input i_rst_n,   //复位信号
                  input i_signal,  //  输入信号   待检测信号
                
                  output  out_buff  // 打拍缓冲输出信号
                 
                  ); 
          
reg  signal_reg0;
reg  signal_reg1;
reg  signal_reg2;
always @(posedge clk)
begin
   if(!i_rst_n)begin
      signal_reg0 <= 1'b0; 
      signal_reg1 <= 1'b0; 
      signal_reg2 <= 1'b0; 
   end
   else
   begin
      signal_reg0 <= i_signal; 
      signal_reg1 <= signal_reg0 ; 
      signal_reg2 <= signal_reg1 ; 
   end
end
//assign  out_buff   =  signal_reg0 ;    //固定为1拍
//assign  out_buff   =  signal_reg1 ;    //固定为2拍
assign  out_buff   =  signal_reg2 ;    //固定为3拍
endmodule 

细究下边沿检测原理

我将结合时序图 ,并以这段代码为例逐步分析下是如何实现上升沿检测的

module signal_pos(
                  input i_clk,    //时钟输入
                  input i_rst_n,   //复位信号
                  input i_signal,  //  输入信号   待检测信号
                
                  output  pos_pulse  //输出脉冲信号
                  );
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)
begin
   if(!i_rst_n)begin
      signal_reg0 <= 1'b0;
      signal_reg0 <= 1'b0;  
   end
   else
   begin
      signal_reg0 <= i_signal;
      signal_reg1 <= signal_reg0 ; 
   end
end
assign pos_pulse  = ~signal_reg1  &  signal_reg0   //上升沿脉冲  宽度:一个时钟周期
endmodule 

看下面这两句话:

      signal_reg0 <= i_signal;
      signal_reg1 <= signal_reg0 ; 

为了看着方便,我将输入信号 i_signal 替换为 in, signal_reg0 替换为reg0, signal_reg1 替换为reg1

      reg0 <= in;
      reg1 <= reg0 ; 

下面这样图,把打拍的实际电路呈现了出来,打了两排,实际上就是让数据IN经过了两个D触发器缓冲输出,这种打拍方式也用于将数据跟时钟信号同步
至于为上升沿为啥是:~reg1 & reg0 ,根据这张图,不妨这样理解:
在这里插入图片描述

1、先把这两个串联的D触发器理解成一个移位寄存器;
2、上升沿的跳变0 —>1,看成两个进入移位寄存器的数据 :0进入移位寄存器,1后进入移位寄存器;
3、经历一定的时钟周期后,先进入移位寄存器的0,进入了reg1寄存器,后进入的 1,进入了reg0寄存器;
4、reg1中保存的是老状态0,reg0中保存的是新状态1,当检测到相邻的两个D触发器中的数据不同时,说明有跳变沿,所以上升沿就是 ~reg1 & reg0 = 1;
5、因为是采用的相邻的两个D触发器中的数据检测变化,所以4中产生的 ~reg1 & reg0 = 1 也只有一个时钟周期的宽度。
6、要想让检测到的上升沿脉冲信号宽一点,如果你理解了的话,应该知道怎么做了,哈哈!看下图
应该懂了吧!!
在这里插入图片描述
还可以以下图的方式来理解,前提是要对阻塞赋值和非阻塞赋值有比较深刻的理解:
结合流程图时序图可以清楚的看到,上升沿脉冲是在2、3之间产生的。
在这里插入图片描述在这里插入图片描述

  • 9
    点赞
  • 71
    收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论 2

打赏作者

不愿透露姓名的局内人

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值