Verilog实现任意分频和占空比

任意分频模板和技巧ide

(一)   偶数的分频技巧性能

(1)       任意偶数分频(占空比为50%)的模板优化

/******************** N  dividen clk   (1:1) duty  Template ***************/spa

module clk_div(设计

     inputclk_100,3d

     output clk_outcode

);blog

 

/********* 10 dividen clk 1:1 duty   success *********/ip

//  1--2--3--4--5-- ...--9--0--1  10分频就只须要10个状态ci

parameter N =4'd8;  // here replace: 14, 12, 10, 8, 6, 4, 2

reg [3:0] cnt =4'd0;

always@(posedge clk_100)

begin

    if(cnt == (N-1) )

       cnt <= 4'd0;

    else

       cnt <= cnt + 1'b1;

end

 

reg clkout =1'b0;

always@(posedge clk_100)

begin

  if(cnt == 4'd0)

    clkout <= 1'b1;

  else if(cnt == (N/2))

    clkout <= 1'b0;

  else

    clkout <= clkout;

end

 

assign clk_out =clkout;

 

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

上面的仿真图:

 

(2)       任意偶数分频(占空比为任意)的模板

 

/********************偶数任意分频 占空比为 (N/2+X):(N/2-X)的 模板  success ***************/

module clk_div(

     inputclk_100,

     output clk_out

);

 

//  1--2--3--4--5-- ...--9--0--1  10分频就只须要10个状态

parameter N =4'd8;  // 14, 12, 10, 8 ,6 ,4 ,2

parameter X =4'd2;

 

reg [3:0] cnt =4'd0;

always@(posedge clk_100)

begin

    if(cnt == (N-1) )

       cnt <= 4'd0;

    else

       cnt <= cnt + 1'b1;

end

 

reg clkout =1'b0;

always@(posedge clk_100)

begin

  if(cnt == 4'd0)

    clkout <= 1'b1;

  else if(cnt == (N/2 + X))

    clkout <= 1'b0;

  else

    clkout <= clkout;

end

 

assign clk_out =clkout;

 

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

上面的仿真图:

 

 

(二)   奇数的分频技巧

(1)       任意奇数分频(占空比为50%)的模板

/*******************************  任意奇数分频 (占空比为50%)************************************/

module clk_div(

     inputclk_100,

     output clk_out

);

 

parameter N =9;   // Dividend

reg [3:0] cnt_p= 0;

always@(posedge clk_100)

begin

    if(cnt_p == N-1)

      cnt_p <= 4'd0;

    else

     cnt_p<= cnt_p + 1'b1;

end

reg clk_p = 0;

always@(posedge clk_100)

begin

    if(cnt_p == (N-1)/2)

      clk_p <= ~clk_p;

     elseif(cnt_p == (N-1))

      clk_p <= ~clk_p;

     else

      clk_p <= clk_p;

end

 

reg [3:0] cnt_n= 0;

always@(negedge clk_100)

begin

   if(cnt_n == N-1)

      cnt_n <= 4'd0;

     else

      cnt_n <= cnt_n + 1'b1;

end

reg clk_n = 0;

always@(negedge clk_100)

begin

    if(cnt_n == (N-1)/2)

      clk_n <= ~clk_n;

     elseif(cnt_n == (N-1))

      clk_n <= ~clk_n;

     else

      clk_n <= clk_n;

end

 

assign clk_out =clk_n | clk_p;

 

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

 仿真图以下:


(2)       任意奇数分频(占空比为任意)的模板

/********************************************任意分频要点和注意事项*******************************************************

1. 公式: fi*K = fo*2^32      fi -- 输入频率    fo -- 输出频率   k -- 计数步长

2. 占空比问题:  用这种方式求占空比问题时候,若是是是奇数分频,那么不能求到准确的1:1占空比。 (好比咱们求5分频,那么咱们只能求1/5的整数倍的占空  比) 在求准确的占空比时候,好比咱们在5分频时候,那么能够跟2^32/5 的整数倍(1~4)进行比较,而后输出高低电平,进而输出必定的占空比

3. 弊端: 任意分频只能求必定的占空比,不能求1:1占空比. 这是它的弊端。     

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

/*******************************  任意分频 ************************************/

//  fout*2^32 = fin*K      k = fout*2^32/fin = 20*2^32/100 = 2^32/5

//   2^32 = 4294967296;   

//   2^32/2 = 32'd2147483648;

//   2^32/5 = 32'd858993459

 

parameter K =32'd858993459;   //  2^32/5 = 858993459         步长为 2^32/5  因此可使用步长的整数倍来进行分频时候使用

parameter X =4'd2;  // 1, 2 ,3 ,4

reg [31:0] cnt =32'd0;

always@(posedge clk_100)

begin

  cnt <= cnt + K;

end

 

reg clkout;

always@(posedge clk_100)

begin

   if(cnt <= X*K)   //  cnt< 2*2^32/5 --- 占空比为  3:2    

    clkout<= 1'b0;

  else

    clkout<= 1'b1;

end

 

assign clk_out =clkout;

 

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

下面是仿真图:

    


注意:

        门控时钟指的是不用FPGA内部的全局时钟资源BUFG来控制触发器的时钟沿输入端而是采用组合逻辑和其它时序逻辑(如分频器)产生的信号做为触发器的时钟沿输入端。门控时钟容易带来时钟漂移、毛刺等,使得触发器误动做,一般,对于驱动的触发器数量较少的门控时钟,编译器能够自动将分布时钟缓冲器将其布线优化,可是对于驱动触发器较多的门控时钟,将会使布线不稳定,重者形成设计混乱。门控时中较多,也会使得整个设计的最大工做速度降低,下降产品的性能。


   咱们不能直接使用门控时钟,最好使用使能时钟。 下面就是使能时钟的生成: 设 clkout 是由组合逻辑或者分频计数实现的时钟,clk_out  是咱们最终生成的时钟。

reg[1:0] clkout1;
always@(posedge clk_100) 
begin
  clkout1 <= {clkout1[0], clkout};
end

assign clk_out = ~clkout1[0]&&clkout1[1] ? 1'b1 : 1'b0;


/***************************************************************  for example  *******************************************************************

`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company:  // Engineer:  //  // Create Date:    10:59:16 08/09/2015  // Design Name:  // Module Name:    clk_div  // Project Name:  // Target Devices:  // Tool versions:  // Description:  // // Dependencies:  // // Revision:  // Revision 0.01 - File Created // Additional Comments:  // ////////////////////////////////////////////////////////////////////////////////// module clk_div( input clk_100,   // output [1:0]cnta, // output [1:0]cntb, output cnta, output cntb, output clk_out       );   /******************** 偶数任意分频 占空比为50%模板  1:1 duty   success *************** //  1--2--3--4--5-- ...--9--0--1  10分频就只须要10个状态 parameter N = 4'd8;  // 14, 12, 10, 8 ,6 ,4 ,2  reg [3:0] cnt = 4'd0; always@(posedge clk_100) begin      if(cnt == (N-1) )    cnt <= 4'd0;     else    cnt <= cnt + 1'b1; end reg clkout = 1'b0; always@(posedge clk_100) begin   if(cnt == 4'd0)     clkout <= 1'b1;   else if(cnt == (N/2))     clkout <= 1'b0;   else     clkout <= clkout; end assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /***********************************************************************************/ /******************** 偶数任意分频 占空比为 (N/2+X):(N/2-X)的 模板   success *************** //  1--2--3--4--5-- ...--9--0--1  10分频就只须要10个状态 parameter N = 4'd8;  // 14, 12, 10, 8 ,6 ,4 ,2  parameter X = 4'd2; reg [3:0] cnt = 4'd0; always@(posedge clk_100) begin      if(cnt == (N-1) )    cnt <= 4'd0;     else    cnt <= cnt + 1'b1; end reg clkout = 1'b0; always@(posedge clk_100) begin   if(cnt == 4'd0)     clkout <= 1'b1;   else if(cnt == (N/2 + X))     clkout <= 1'b0;   else     clkout <= clkout; end assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /***********************************************************************************/ /*************   2 dividen clk  right ******************* reg clk_R = 1'b0; always@(posedge clk_100) begin   clk_R = ~ clk_R;   end assign clk_out = clk_R; /*******************************************************/ /******************** 4 dividen clk 3:1 duty   success *************** //  1--2--3--0--1  4分频就只须要4个状态 reg [1:0] cnt = 2'd0; always@(posedge clk_100) begin      if(cnt == 2'd3)    cnt <= 2'd0;     else    cnt <= cnt + 1'b1; end reg clkout = 1'b0; always@(posedge clk_100) begin   if(cnt == 2'd1)     clkout <= 1'b1;   else if(cnt == 2'd0)     clkout <= 1'b0;   else     clkout <= clkout; end assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /***********************************************************/ /******************** 6 dividen clk 4:2 duty   success *************** //  1--2--3--4--5--0--1  6分频就只须要6个状态 reg [2:0] cnt = 3'd0; always@(posedge clk_100) begin      if(cnt == 3'd5)    cnt <= 3'd0;     else    cnt <= cnt + 1'b1; end reg clkout = 1'b0; always@(posedge clk_100) begin   if(cnt == 3'd1)     clkout <= 1'b1;   else if(cnt == 3'd5)     clkout <= 1'b0;   else     clkout <= clkout; end assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /***********************************************************/ /******************** 偶数任意分频 占空比为50%模板  1:1 duty   success *************** //  1--2--3--4--5-- ...--9--0--1  10分频就只须要10个状态 parameter N = 4'd8;  // 14, 12, 10, 8 ,6 ,4 ,2  reg [3:0] cnt = 4'd0; always@(posedge clk_100) begin      if(cnt == (N-1) )    cnt <= 4'd0;     else    cnt <= cnt + 1'b1; end reg clkout = 1'b0; always@(posedge clk_100) begin   if(cnt == 4'd0)     clkout <= 1'b1;   else if(cnt == (N/2))     clkout <= 1'b0;   else     clkout <= clkout; end assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /***********************************************************************************/ /***************** 3 dividen clk  error ***************** //This code looks like right,and simulation shows right // But it is wrong. reg [2:0] cnt = 3'd0; reg clk_R = 1'b0; always@(clk_100) begin     if(cnt < 3'd3)  cnt = cnt + 1'b1;    if(cnt == 3'd3) begin      clk_R = ~ clk_R;   cnt = 3'd0;     end   end assign clk_out = clk_R; /*********************************************************/ /***************** 3 dividen clk  success ***************** reg [1:0] cnt_a = 0; always@(posedge clk_100) begin   if(cnt_a == 2'b10)      cnt_a <= 2'd0;   else      cnt_a <= cnt_a + 1'b1; end  reg [1:0] cnt_b = 0; always@(negedge clk_100) begin   if(cnt_b == 2'b10)      cnt_b <= 2'd0;   else      cnt_b <= cnt_b + 1'b1; end  reg clk_R = 1'b0; always@(cnt_a or cnt_b) begin  if((cnt_a + cnt_b == 3'd4) || (cnt_a + cnt_b == 3'd1)) clk_R <= ~ clk_R;  else clk_R <= clk_R;   end assign clk_out = clk_R; assign cnta = cnt_a; assign cntb = cnt_b; /*********************************************************/ /******************   3 dividen clk  success  ********************** reg q1,q2,d,throut; initial begin  d  = 0;  q1 = 0;  q2 = 0;  throut = 0; end  always @(posedge clk_100) if(!d)   q1=1'b1; else   q1=~q1; always @(negedge clk_100) if(!d) q2=1'b1; else q2=~q2; always @(q1 or q2)    d=q1&q2; always @(posedge d)    throut=~throut; assign clk_out = throut; /*******************************************************************/ /********************* 3 dividen clk  success duty50%  ********************** reg [1:0] step1, step;  always @(posedge clk_100) begin case (step)   //这个状态机就是一个计数器 2'b00: step<=2'b01; 2'b01: step<=2'b10; 2'b10: step<=2'b00; default :step<=2'b00; endcase end always @(negedge clk_100)  //step1与step相差半个clk begin case (step1) 2'b00: step1<=2'b01; 2'b01: step1<=2'b10; 2'b10: step1<=2'b00; default :step1<=2'b00;     endcase end assign clk_out = step[1] | step1[1]; //利用step和step1高位的或运算,实如今1.5个clk时翻转。 /***********************************************************************************/ /********************* 5 dividen clk success duty50% ********************** reg [2:0] step1, step2; always@(posedge clk_100) begin case (step1) 3'b000: step1<=3'b001; 3'b001: step1<=3'b011; 3'b011: step1<=3'b100; 3'b100: step1<=3'b010; 3'b010: step1<=3'b000; default:step1<=3'b000; endcase end always@(negedge clk_100) begin  case (step2) 3'b000: step2<=3'b001; 3'b001: step2<=3'b011; //注意调换了顺序,目的为了使最低位为1的状况互邻 3'b011: step2<=3'b100; 3'b100: step2<=3'b010; 3'b010: step2<=3'b000; default:step2<=3'b000; endcase end assign clk_out = (step1[0]|step2[0]); //step1与step2 最低位相或 assign cnta = 2'b11; assign cntb = 2'b11; /********************* 5 dividen clk success  50%duty ********************** reg [2:0] cnt_p = 0; reg [2:0] cnt_n = 0; reg clk_p = 0; reg clk_n = 0; parameter N = 5; //  posedge clk   0-1-2-3-4-0 always@(posedge clk_100) begin  if(cnt_p==N-1)    cnt_p <=0;  else cnt_p <= cnt_p + 1; end always@(posedge clk_100) begin  if(cnt_p==(N-1)/2)   //2      clk_p <= !clk_p;  else if(cnt_p==N-1)      clk_p <= !clk_p; //4 end // negedge clk   0-1-2-3-4-0 always@(negedge clk_100 ) begin  if(cnt_n==N-1)           cnt_n <=0;    else       cnt_n <= cnt_n + 1; end always@(negedge clk_100) begin  if(cnt_n==(N-1)/2)      clk_n <= !clk_n;  else if(cnt_n==N-1)      clk_n <= !clk_n; end assign clk_out = clk_p | clk_n; //***********  for simulation  ************** //assign cnta = clk_p; //assign cntb = clk_n; //******************************************* assign cnta = 2'b11; assign cntb = 2'b11; /*********************************************************/ /*******************************  5 分频  ************************************ //  fout*2^32 = fin*K      k = fout*2^32/fin = 20*2^32/100 = 2^32/5 //   2^32 = 4294967296;     //   2^32/2  = 32'd2147483648; //   2^32/5  = 32'd858993459  parameter K = 32'd858993459;   //  2^32/5 = 858993459 reg [31:0] cnt = 32'd0; always@(posedge clk_100)  begin   cnt <= cnt + K; end  reg clkout; always@(posedge clk_100)  begin    if(cnt < 32'd2147483648)   //  cnt < 2^32/5---占空比为  4:1     cnt < 2^32/2---占空比为  1:1  clkout <= 1'b0; else  clkout <= 1'b1;  end  assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /*****************************************************************************/ /********************* 7 dividen clk duty = 50%  success ********************** reg [2:0] cnt_p = 0; reg [2:0] cnt_n = 0; reg clk_p = 0; reg clk_n = 0; parameter N = 7; always@(posedge clk_100) begin  if(cnt_p == N-1)    cnt_p <= 3'd0;  else    cnt_p <= cnt_p + 1'b1; end always@(posedge clk_100) begin   if(cnt_p == (N-1)/2)    clk_p <= ~ clk_p;   else if(cnt_p == (N-1))     clk_p <= ~ clk_p;   else     clk_p <= clk_p; end always@(negedge clk_100) begin  if(cnt_n == N-1)    cnt_n <= 3'd0;  else    cnt_n <= cnt_n+ 1'b1; end always@(negedge clk_100) begin   if(cnt_n == (N-1)/2)    clk_n <= ~ clk_n;   else if(cnt_n == (N-1))     clk_n <= ~ clk_n;   else     clk_n <= clk_n; end assign cnta = clk_p; assign cntb = clk_n; assign clk_out = clk_p | clk_n; /********************************************************/ /******************************************** 任意分频要点和注意事项 ******************************************************* 1. 公式:  fi*K = fo*2^32      fi -- 输入频率    fo -- 输出频率   k -- 计数步长 2. 占空比问题:  用这种方式求占空比问题时候,若是是是奇数分频,那么不能求到准确的1:1占空比。 (好比咱们求5分频,那么咱们只能求1/5的整数倍的占空比)              在求准确的占空比时候,好比咱们在5分频时候,那么能够跟 2^32/5 的整数倍(1~4)进行比较,而后输出高低电平,进而输出必定的占空比 3. 弊端:  任意分频只能求必定的占空比,这是它的弊端。       /**********************************************************************************************************************/ /*******************************  任意分频  ************************************ //  fout*2^32 = fin*K      k = fout*2^32/fin = 20*2^32/100 = 2^32/5 //   2^32 = 4294967296;     //   2^32/2  = 32'd2147483648; //   2^32/5  = 32'd858993459  parameter K = 32'd858993459;   //  2^32/5 = 858993459         步长为 2^32/5  因此可使用步长的整数倍来进行分频时候使用 parameter X = 4'd2;  //  1, 2 ,3 ,4  reg [31:0] cnt = 32'd0; always@(posedge clk_100)  begin   cnt <= cnt + K; end  reg clkout; always@(posedge clk_100)  begin    if(cnt < X*K)   //  cnt < 2*2^32/5---占空比为  3:2      if(cnt <= X*K)  clkout <= 1'b0; else  clkout <= 1'b1;  end  assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /*****************************************************************************/ /*******************************  任意奇数分频 (占空比为50%)  ************************************/ parameter N = 9;   //  Dividend reg [3:0] cnt_p = 0; always@(posedge clk_100)  begin     if(cnt_p == N-1)   cnt_p <= 4'd0; else cnt_p <= cnt_p + 1'b1; end  reg clk_p = 0; always@(posedge clk_100)  begin     if(cnt_p == (N-1)/2)   clk_p <= ~clk_p; else if(cnt_p == (N-1))   clk_p <= ~clk_p; else   clk_p <= clk_p; end  reg [3:0] cnt_n = 0; always@(negedge clk_100)  begin     if(cnt_n == N-1)   cnt_n <= 4'd0; else   cnt_n <= cnt_n + 1'b1; end  reg clk_n = 0; always@(negedge clk_100)  begin     if(cnt_n == (N-1)/2)   clk_n <= ~clk_n; else if(cnt_n == (N-1))   clk_n <= ~clk_n; else   clk_n <= clk_n; end  assign clk_out = clk_n | clk_p; assign cnta = 1'b1; assign cntb = 1'b1; /*****************************************************************************/         /***********************************  7分频  占空比为 4:3  success ********************************* //  2^32*fout = K*fin;    fin=100  fout=100/7= 14.285714285714285714285714285714 parameter K = 32'd613566756;  //  2^32*fout/fin = k = 2^32/7 = 613566756      4*k = 2454267026 reg [31:0] cnt = 32'd0; always@(posedge clk_100) begin   cnt <= cnt + K; end reg clkout = 1'b0; always@(posedge clk_100) begin   if(cnt <= 32'd2454267026)   //  4*k     clkout <= 1'b1;   else     clkout <= 1'b0; end assign clk_out = clkout; assign cnta = 1'b1; assign cntb = 1'b1; /****************************************************************************************/ endmodule