FPGA延时Verilog HDL实现

描述

 

本章节简介:

可以在任意时刻启动,可以重复启动,延时时长可调,单位可切换(ms/us),在50MHz时钟下的延时范围是1ms-85899ms/1us-85899us。

源代码和modelsim仿真代码:

 

 module delay



 //#(parameter N )  //可以延时N*1ms/us



  (input clk,rst_n,

   input start,     //start上升沿有效

   input delay_unit, //延时单位,high:ms/low:us

   output finish,finish_pose); //finish上升沿有效

   reg start_reg0,start_reg1;  //start两级缓存,用于边沿检测

   reg finish_reg0,finish_reg1;  //finish两级缓存

   reg [31:0]cnt;  //固定32位宽计数

   reg [31:0]cnt_full;

   reg restart; //重新开始

   wire start_pose,full;

   always @(posedge clk or negedge rst_n)

        begin

            if(!rst_n)

               begin 

                   cnt <= 32'd0;

                   cnt_full <= 32'd10; //避免一开始finish置位

                   restart <= 1'b0;

                   start_reg0 <= 1'b0; start_reg1 <= 1'b0; 

                   finish_reg0 <= 1'b0; finish_reg1 <= 1'b0;

               end

           else

              begin

                  start_reg0 <= start; start_reg1 <= start_reg0;

                  finish_reg1 <= finish_reg0;  

                  /**检测计时单位**/

                  if(delay_unit)  

                     cnt_full <= 32'd50_000*2-32'd2;  //计时2ms  实际例化时用N代替: 32'd50_000*N-32'd2

                  else

                     cnt_full <= 32'd50*2-32'd2;      //计时2us

                 /***************/

                /**是否重新开始**/

                if(start_pose)  //检测到起始时刻 

                    restart <= 1'b1;  

               /****计时完成****/

               else if(full)  //延时结束

                  begin

                      cnt <= 32'd0;  //cnt归零

                      finish_reg0 <= 1'b1;  //finish响应

                      restart <= 1'b0;

                  end

             /***************/

             /****计时开始****/

             else if(restart) 

                begin

                    finish_reg0 <= 1'b0;    //新一轮延时finish复位

                    cnt <= cnt+1'b1;

                end

           /***************/

           /**等待新一轮计时**/

           else 

              begin

                  cnt <= cnt;

                  finish_reg0 <= finish_reg0;

                  restart <= restart;

              end

    end  

end

 

  assign start_pose = (~start_reg1&start_reg0)?1'b1:1'b0;  //start上升沿检测

  assign finish_pose = (~finish_reg1&finish_reg0)?1'b1:1'b0;  //finish上升沿检测

  assign full = (cnt_full-cnt==0)?1'b1:1'b0;   //检测是否计满



  assign finish = finish_reg0;



endmodule



/**************************************************************************************************/                                     /***************************************modelsim********************************************/  



`timescale 1ns/1ps

module delay_tb();

   reg clk,rst_n;

   reg start;

   wire finish,finish_pose;

  

  delay delay_u0

  (.clk(clk),

   .rst_n(rst_n),

   .start(start),

   .delay_unit(1'b1),

   .finish(finish),

   .finish_pose(finish_pose));

   //defparam delay_u0.N = 2; //延时2ms

  

  initial

    begin

clk = 1'b0;

        rst_n = 1'b0;

        start = 1'b0;

#1000 rst_n = 1'b1;

#4010 start = 1'b1;                                                                                                                                                                 #50     start = 1'b0;                                                                                                                                                            end



  always #10 clk = ~clk;

endmodule

 

思路:

start端口给上升沿启动延时,延时结束端口finish置位(重新启动延时后复位)、finish的上升沿检测在模块内部已做好(端口finish_pose),直接调用即可,端口delay_unit置高选择ms,置低选择us,#(参数N )“是计时时长,例如计时8ms:”N = 8, .delay_unit(1'b1)“,实际例化时只需”defparam 例化名.N = 数值”。因为modelsim无法识别这种调用,所以直接用数值代替N进行测试。边沿检测会消耗两个时钟周期,所以cnt_full需要减2,并且将finish_reg0直接连到finish输出端口而不是用finish_reg1连接完成。

延时2ms测试的起始时刻(5010ns)和结束时刻(2005010ns):

VerilogVerilog

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分