FPGA基础学习——Verilog实现的边沿检测(上升沿下降沿检测)及Modelsim仿真

//学习笔记//


1、什么是边沿检测 ?

检测输入信号或FPGA内部逻辑信号的跳变,即上升沿或者下降沿的检测。

2、边沿检测的方法

设置两个寄存器,对前一状态和后一状态进行寄存,若前后两个状态不同,则检测到了边沿。对于上升沿和下降沿的确定可以用组合逻辑比较来确定。若前一状态D[1]为高电平,后一状态D[0]为低电平,则为下降沿,反之为上升沿。
在这里插入图片描述

3、Verilog实现边沿检测

用Verilog实现的1bit信号边沿检测功能,输出一个周期宽度的脉冲信号。

module test(


      input       clk,
	   input       rst_n,
		input       data,
		
		output      pos_edge,    //上升沿
		output      neg_edge,    //下降沿  
		output      data_edge,  //数据边沿
		
		output reg     [1:0]   D      
);
	
//设置两个寄存器,实现前后电平状态的寄存
//相当于对dat_i 打两拍

	always @(posedge clk or negedge rst_n)begin
	    if(rst_n == 1'b0)begin
	        D <= 2'b00;
	    end
	    else begin
	        D <= {D[0], data};  	//D[1]表示前一状态,D[0]表示后一状态(新数据) 
	    end
	end
	
//组合逻辑进行边沿检测

	assign  pos_edge = ~D[1] & D[0];
	assign  neg_edge = D[1] & ~D[0];
	assign  data_edge = pos_edge | neg_edge;
	
endmodule

RTL图:
在这里插入图片描述

tb仿真文件:

`timescale 1ns/1ns

module test_tb;
   reg        clk;
	reg        rst_n;
	reg        data;
	
	wire       pos_edge;
   wire       neg_edge;
   wire       data_edge;
	wire [1:0] D;


  test   u1(
      .clk(clk),
      .rst_n(rst_n),
      .data(data),
    
      .pos_edge(pos_edge),
      .neg_edge(neg_edge),
      .data_edge(data_edge),
		.D(D)
 );
 
 //产生时钟激励
 initial  clk = 1; 
 always #10  clk = ~clk;

 
 //输入激励
 initial  begin 
      rst_n=0;
		data=0;
      #100;
      rst_n = 1;
		#50
      data=1;
      #201;
      data=0;
      #201;
      data=1; 
      #101;
      data=0;	
      #200;
      $stop;
 
 end
 
 endmodule 

波形图:
通过波形图进行分析,可看到data数据中有上升下降沿的变化,因此我们可对其进行检测。
在这里插入图片描述

上升沿检测:
看红色方框部分,当检测到上升沿的时候,pos_edge出现一个clk的高脉冲,同时边沿信号也出现一个clk高脉冲。

下升沿检测:
看蓝色方框部分,当检测到下降沿的时候,neg_edge出现一个clk的高脉冲,同时边沿信号也出现一个clk高脉冲。


4、上升沿、下降沿和数据沿是如何写出来的?

首先以时钟的上升沿作为参考,然后进行时序分析。

信号打拍:
要边沿信号检测,那么我们需要知道信号前后时刻的电平状态才能进行判断。因此采用两个寄存器来对状态进行存储。
首先会将data进行打拍,先打一拍进行本地同步,在再打一拍用于逻辑运算生成脉冲。打2拍处理后,于是有reg [1:0] D
其中D[0]表示后一状态,D[1]表示前一状态
在这里插入图片描述

其中上升沿、下降沿、边沿如下:
红色部分为上升沿
蓝色部分为下降沿
绿色为边沿。
当检测上升沿时,看第一个黑色方块,此时D[0]高电平,D[1]低电平,因此 得到上升沿:assign pos_edge = ~D[1] & D[0];
当检测下降沿时,看第二个黑色方块,此时D[0]低电平,D[1]高电平,因此 得到下降沿: assign neg_edge = D[1] & ~D[0];
在这里插入图片描述


数据边沿检测:

上升下降沿进行或运算

assign  data_edge = pos_edge | neg_edge;

在这里插入图片描述


5、亚稳态问题(多加一级寄存器来解决)

综上分析可以发现这种方法存在一个潜在风险:当待测信号data是一个异步信号时,输出可能是亚稳态,如果data信号的变化刚好发生在clk时钟的建立时间和保持时间之内,那么第一级寄存器的输出 data[0] 就会进入亚稳态,而data[0] 的亚稳态会立即传递给pos_edge和neg_edge信号,从而使得整个电路的输出进入亚稳态,影响下一级电路的正常工作,甚至导致整个系统崩溃!因此异步信号边沿提取时,应先将异步信号同步化,一般采用多加一级寄存器的方法来解决亚稳态。
在这里插入图片描述

亚稳态:指触发器输出无法再某一个规定时间段内达到一个确定的状态(0或1)。
建立时间(setup time)是指在触发器的时钟信号上升沿到来以前,数据稳定不变的时间,如果建立时间不够,数据将不能在这个时钟上升沿被打入触发器;
保持时间(hold time)是指在触发器的时钟信号上升沿到来以后,数据稳定不变的时间,如果保持时间不够,数据同样不能被打入触发器。


在这里插入图片描述Tsu:建立时间
Th:保持时间
Tco:寄存器内部延迟时间

上图pulse信号的变化在 clk时钟的建立和保持时间内,那么pulse_r1可能会进入亚稳态。
一般情况下,亚稳态的决断时间(即进入亚稳态到稳定下来的时间)不会超过一个时钟周期,因此在下一个clk上升沿到来前,pulse_r1已稳定下来(0或1),此时第二级寄存器就会采集到一个稳定的0或1,把亚稳态限制在第二级寄存器之前,保证了整个电路输出的稳定性。

综上所述,在异步信号边沿检测电路中,至少需要采用三级寄存器来实现,来降低亚稳态发生概率,提高系统稳定性。


Verilog代码编写三级寄存器避免亚稳态现象出现,实现异步信号边缘检测


module test(clk, rst_n,pulse,pos_edge,neg_edge,data_edge);

	 input clk, rst_n;
    input pulse;
	 output pos_edge;
	 output neg_edge;
	 output data_edge;
	
	 reg pulse_r1, pulse_r2, pulse_r3;

//打三拍来消除亚稳态
always @ (posedge clk or negedge rst_n) //异步
 if(!rst_n) 
    begin
	    pulse_r1 <= 1'b0;
	    pulse_r2 <= 1'b0;
	    pulse_r3 <= 1'b0;
    end
 else 
    begin
	    pulse_r1 <= pulse;
	    pulse_r2 <= pulse_r1;
	    pulse_r3 <= pulse_r2;
    end
	 
//边沿检测
    
assign pos_edge = pulse_r2 & ~pulse_r3;
assign neg_edge = ~pulse_r2 & pulse_r3; 
assign data_edge = pos_edge | neg_edge; 

endmodule

testbench仿真文件

`timescale 1ns/1ns
`define clock_period  20
module test_tb;
	   
	   reg clk;
		reg rst_n;
		reg pulse;
		
		wire pos_edge;
	   wire neg_edge;
		wire data_edge;
	
	  test  u1(
	   .clk(clk),
	   .rst_n(rst_n),
		.pulse(pulse),
		.pos_edge(pos_edge),
		.neg_edge(neg_edge),
		.data_edge(data_edge)
	 );
	 
//产生时钟复位激励
	 initial  clk = 1;
	 always #(`clock_period/2)  clk =~clk;
	 
	 initial  begin 
	 rst_n = 0;
	 #10;
	 rst_n = 1;
	 end
	 
//产生输入激励	 
initial  begin 
	  
	  pulse=0;
	  #(`clock_period*10+1)
	  pulse=1;
	  #(`clock_period*10+1)
	  pulse=0;  
	  #(`clock_period*10+1)
	  pulse=1;
	  #(`clock_period*5+1)
	  pulse=0;
	  #(`clock_period*200+1)
	  pulse=0;
	  #(`clock_period*10)
	  $stop;
	 end 
endmodule 

全局波形图:
可看到我们打了三拍,可避免亚稳态的出现。让根据输入pulse进行了上升下降以及边沿检测。
在这里插入图片描述
上升沿检测波形:
在这里插入图片描述
下降沿检测:
在这里插入图片描述
边沿检测:
在这里插入图片描述

  • 106
    点赞
  • 410
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting_FPGA

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值