Verilog触发设计

来源:互联网 发布:linux 输出重定向 编辑:程序博客网 时间:2024/06/04 19:26

首先外部信号相对于内部时钟是一个异步的信号,做同步处理是很重要的,能够很好的避免毛刺(错误的)的出现。 但是触发信号引入的时钟偏差需要在单片机处理的时候做一下校正.

   (1) 边沿触发的时候不是使用外部信号的上升沿,而是首先利用2个D触发器,通过检测触发器输出的信号来判断边沿的情况。这种方法即把时钟同步带FPGA的时钟域,也很好的进行边沿的检测,不过要注意一个问题,就是竞争现象,如果D触发器的数据输出在上升沿,数据的检测也在上升沿就会出现触发位置的偶然偏差,如果检测放在下降沿就会很好的避免 这种情况

/**********************边沿检测代码 ********************************/

 always@(posedge clk or negedge rst) 
  begin 
  if(!rst) 
   begin 
    d_0<=1'bx; 
   d_1<=1'bx; 
   end 
else  
   begin 
   d_0 <= data_in; 
   d_1 <= d_0; 
   end 
 end 


/*********************边沿的判断*****************************************/ 
always@(negedge clk or negedge rst)// competition if detect in posdege注意竞争现象 
begin 
if(!rst) 
trigger <= 1'b0; 
else 
       begin 
if(d_1==1'b0 && d_0==1'b1) 
              trigger<=1'b1; 
       end  
  end 
/****************************************************************************/

 (2) 电平的触发和边沿触发相似,只是在第二个always触发条件成立的条件改一下就可以了 
  (3)字触发 :单级的字触发很简单,但是设计中引入的fifo满的时候不确定问题会使触发位置有10%的概率出现位置不是在边沿,为了解决这个问题,在设计的时候使用边沿检测手段,只不过触发器和比较器变成8位.

/*******************************************************/
always @( posedge clk or negedge rst) 
        begin 
        if(!rst) 
        begin 
          d_0 <= 8'bxxxxxxxx; 
          d_1 <= 8'bxxxxxxxx; 
        end 
        else 
        begin 
          d_0 <= data_in; 
          d_1 <= d_0; 
        end  
        end 
         
always@(negedge clk or negedge rst) 
begin 
if(!rst) 
begin   
trigger <= 1'b0; 
end 
else if((d_0  ==  trigger_word) && (d_1 != trigger_word)) //2次的数据不一样,才能够触发 
            trigger <= 1'b1; 
        end       
/*****************************************************************/ 

       多级的字触发必须借助状态机来实现,通过状态之间的转换来实现,这里fifo引入的不确定问题对触发没有影响 

   (4)脉宽触发

    以高电平大于等于为例:信号首先经过系统时钟的一个同步,然后控制计数器的工作状态,在数据是低电平的时候,计数器内部的复位 信号有效,计数器处于0的状态;在data有效后,首先会将计数器恢复能够工作的状态,然后开始计数,如果中间的计数值大于设定值,那么触发信号有效,计数器清零位有效,直到复位信号, 鉴于FIFO满信号的时候输入数据的不确定,首先检测数据流中的边沿,然后才使能该模块,避免不确定带来的触发不稳定, 数据进入后先经过一个时钟同步,然后第二个时钟使内部计数器的清零信号无效,在计数器的值达到要求之后, 下一个时钟使触发控制信号有效,接着的一个时钟使触发信号有,所以会有四个时钟的偏移, 其他的脉宽触发的原理是一样的,只不过在判断的条件上做了修改而已.

 ///////////////////////////高脉冲大于等于的代码////////////////////////////////////////////////////////// 

//信号同步到系统时钟 
always @ ( posedge clk or negedge rst) 
begin 
if(!rst) 
data <= 1'b0; 
else 
begin 
                if(valid)           //使能有效后,数据才可以进入,否则数据为0 
                    data <= data_in; 
                else 
                    data <= 1'b0;      
            end    
end 
 //脉冲宽度测量,data作为控制信号 
always@(negedge rst or posedge clk) 
        begin 
        if(!rst ) 
                cnt <= 16'h0000; 
           else if(rst_cnt) 
          cnt <= 16'h0000; 
           else if(data) 
                cnt <= cnt + 16'h0001;          
        end 
 //同时检测数据的大小 如果数据大于设定的脉宽,发送触发条件,计数器清零位有效

//如果不满足触发条件,那么data低电平清除计数器的值,高电位使能其

always@(negedge rst or negedge clk ) 
        begin 
        if(!rst) 
           begin 
                tri_valid <= 1'b0; 
                rst_cnt   <= 1'b0; 
           end 
           else if(data) 
           begin 
           if(cnt >= pulse_length) 
            begin 
            tri_valid <= 1'b1; 
            rst_cnt   <= 1'b1; 
           end 
           else 
            begin 
            tri_valid <= 1'b0;  
            rst_cnt   <= 1'b0; 
           end 
                end 
          else  if(!data) 
                begin 
           tri_valid <= 1'b0;  
                    rst_cnt   <= 1'b1; 
                end 
        end 
 //触发信号锁存 
always @(negedge rst or posedge tri_valid) 
        begin 
            if(!rst) 
                trigger_ok <= 1'b0; 
            else 
                trigger_ok <= 1'b1;   
        end 
    ///////////////////////////////////////////////////// 
  为了解决fifo满的时候不确定带来的问题,信号进入的时候需要首先检测到边沿然后使能valid信号,才能产生触发条件 ,代码可以参考边沿触发。 

0 0