我是靠谱客的博主 落后日记本,最近开发中收集的这篇文章主要介绍Verilog学习心得之五-----时钟分频器,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

时钟整数分频分为奇数和偶数分频,偶数分频较为简单,假如需要进行偶数为N倍分频,则只需对原输入时钟进行从零开始计数count,当计数值count计数到N/2-1,只需将输出时钟反向即可,RTL代码和测试波形如下:

`timescale  1ns/1ps
module clk_div_even(clk_in,rst_n,clk_out);

input  clk_in;  
input  rst_n;

output clk_out;
reg    clk_out;

parameter   N = 16; //????
parameter   COUNT = N/2 - 1;  //????

reg  [3:0]  count;

always @(posedge clk_in or negedge rst_n)
begin
   if(!rst_n)
     count <= 4'b0;
   else if(count == COUNT)
     count <= 4'b0;
   else
     count <= count + 1'b1;
end 

always @(posedge clk_in or negedge rst_n)
begin
    if(!rst_n)
      clk_out <= 1'b0;
    else if(count == COUNT)
      clk_out <= ~clk_out;
    else
      clk_out <= clk_out;
end

endmodule

`timescale  1ns/1ps
module clk_div_even_tb;

reg       clk_in;
reg       rst_n;
wire      clk_out;
  
clk_div_even  u_clk_div_even(
                             .clk_in(clk_in),                             
                             .rst_n(rst_n),
                             .clk_out(clk_out)
                             );
                             
initial 
begin
  clk_in = 1'b0;
  rst_n = 1'b0;
  #100;
  rst_n = 1'b1;
  #50000;
//  $finish;
end

always #10 clk_in = ~clk_in;

endmodule

对输入时钟进行16分频,仿真波形如下所示:

考虑:当主时钟为高频时,该分频方式是否合适?

假如需要对输入时钟进行奇数分频,如果不要求占空比为50%的话,也比较容易实现,如进行5分频,通过对待分频时钟上升沿触发器进行模5计数,当计数器计数到1时,输出时钟进行翻转,计数到4时再次进行翻转,这样实现的5分频占空比为2/5或者3/5,RTL代码如下所示:

`timescale  1ns/1ps
module clk_div_odd(clk_in,rst_n,clk_out);

input  clk_in;  
input  rst_n;

output clk_out;
reg    clk_out;

parameter   N = 5;

parameter   COUNT1 = 1;
parameter   COUNT2 = 4;
//parameter   COUNT = N/2 - 1;

reg  [3:0]  count;

always @(posedge clk_in or negedge rst_n)
begin
   if(!rst_n)
     count <= 4'b0;
   else if(count == COUNT2)
     count <= 4'b0;
   else
     count <= count + 1'b1;
end 

always @(posedge clk_in or negedge rst_n)
begin
    if(!rst_n)
      clk_out <= 1'b0;
   else if(count == COUNT1)
      clk_out <= ~clk_out; 
   else if(count == COUNT2)
      clk_out <= ~clk_out;
   else
      clk_out <= clk_out;
end

endmodule


对输入时钟进行5分频,仿真波形如下所示:

对于实现占空比为50%的N倍奇数分频,这里介绍两种方式。

方式A:

(1)上升沿触发进行模N计数,计数选定到某一个值进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比为非50%奇数N分频时钟;

(2)下降沿触发进行模N计数,到和上升沿触发输出时钟翻转选定值相同值相同时,进行输出时钟翻转,同样经过(N-1)/2时,输出时钟再次翻转生成占空比为非50%的奇数N分频时钟。

将这两个占空比非50%的N分频时钟或运算,得到占空比为50%的奇数n分频时钟,如下代码为将输入clk_in按占空比为50%进行5分频:

`timescale  1ns/1ps
module clk_div_odd(clk_in,rst_n,clk_out);

input  clk_in;  
input  rst_n;

output clk_out;
//reg    clk_out;

parameter   N = 5;

parameter   COUNT1 = 2;
parameter   COUNT2 = 4;
//parameter   COUNT = N/2 - 1;

reg  [3:0]  count1;
reg  [3:0]  count2;

reg         clk_out1_r;
reg         clk_out2_r;

always @(posedge clk_in or negedge rst_n)
begin
   if(!rst_n)
     count1 <= 4'b0;
   else if(count1 == COUNT2)
     count1 <= 4'b0;
   else
     count1 <= count1 + 1'b1;
end 

always @(negedge clk_in or negedge rst_n)
begin
  if(!rst_n)
     count2 <= 4'b0;
  else if(count2 == COUNT2)
     count2 <= 4'b0;
 
 else
 
    count2 <= count2 + 1'b1; 
end

always @(posedge clk_in or negedge rst_n)
begin
    if(!rst_n)
      clk_out1_r <= 1'b0;
   else if(count1 == COUNT1)
      clk_out1_r <= ~clk_out1_r; 
   else if(count1 == COUNT2)
      clk_out1_r <= ~clk_out1_r;
   else
      clk_out1_r <= clk_out1_r;
end

always @(negedge clk_in or negedge rst_n)
begin
  
  if(!rst_n)
  
    
clk_out2_r <= 1'b0;
 
   else if(count2 == COUNT1)
 
     clk_out2_r <= ~clk_out2_r;
 
   else if(count2 == COUNT2)
 
     clk_out2_r <= ~clk_out2_r;
 
   else
 
     clk_out2_r <= clk_out2_r;
end

assign clk_out = clk_out1_r | clk_out2_r;
endmodule

使用modelsim仿真结果如下所示:

如图所示,clk_out1_r和clk_out2_r占空比都为40%,同时clk_out1_r较clk_out2_r相差90°的相位差,所以将clk_out1_r与clk_out2_r进行或操作即可得到占空比为50%的5分频。

方式B:

在概念上,产生具有50%占空比的奇数分频时钟最简单的方式是以期望输出频率的一半生成两个正交相位时钟(两个时钟之间有90°相位差),然后将两个波形异或得到输出频率。

由于存在固定的90°相位差,每次异或输入只有一端会变化,这样有效消除了波形上的毛刺。

步骤I:创建由时钟上升沿触发的0到(N-1)的计数器,N是自然数,用于对参数时钟进行分频(N不等于偶数)

步骤II:使用两个开关触发器,按以下方式产生其使能信号。

tff1_en:TFF1在计数值为0时使能,tff2_en:TFF2在计数值为(N+1)/2使能。

步骤III:产生以下信号。

div1:TFF1的输出--> 由输入时钟(ref_clk)上升沿触发。 div2:TFF2的输出--> 由输入时钟(ref_clk下降沿触发。

`timescale 1ns/1ps
module clk_div_odd(clk_in,rst_n,clk_out);

input clk_in;
input rst_n;
output clk_out;

parameter N=3;
parameter COUNT1 =2;

reg [1:0] count1;

always @(posedge clk_in or negedge rst_n) begin
    if(!rst_n)
      count1 <= 2'b0;
    else if(count1==2'b10)
      count1<= 2'b0;
    else
      count1 <= count1 + 1'b1;
end

wire tff1_en;
wire tff2_en;
assign tff1_en = (count1 == 2'b00);
assign tff2_en = (count1 == 2'b10);

reg div1_r;
reg div2_r;
always @(posedge clk_in or negedge rst_n) begin
    if(!rst_n)
       div1_r <= 1'b0;
    else if(tff1_en == 1'b1)
       div1_r <= ~div1_r;
    else
       div1_r <= div1_r;
end

always @(negedge clk_in or negedge rst_n) begin
   if(!rst_n)
     div2_r <= 1'b0;
   else if(tff2_en == 1'b1)
     div2_r <= ~div2_r;
   else
     div2_r <= div2_r;
end

assign clk_out = div1_r ^ div2_r;

endmodule

非50%占空比小数分频:

可以考虑采用移位的方式保证输出波形不含毛刺,以4.5倍分频为例:

步骤I:使用复位值为000000001的9位移位寄存器,在每个时钟的上升沿,寄存器左移一位。

步骤II:要产生第1个脉冲,必须使在半周期时移动第一位并将第1位与第2位进行或操作。

步骤III:要产生第2个脉冲,第5位和第6位必须在半周期时移动并与原始第6位进行或操作。

/* counter implementation
   reset value : 9'b000000001 */
always @(posedge ref_clk or negedge rst_n)
    if(~rst_n)
       count[8:0] <= 9'b000000001;
    else
       count[8:0] <= count[8:0] <<1;

always @(negedge ref_clk or negedge rst_n)
    if(~rst_n)
       begin
         ps_count1 <= 1'b0;
         ps_count5 <= 1'b0;
         ps_count6 <= 1'b0;
       end
    else
       begin
         ps_count1 <= count[1];
         ps_count5 <= count[5];
         ps_count6 <= count[6];
       end

assign clkout = (ps_count5 | ps_count6 | count[6]) |
                (count[0] | count[1] | ps_count1);

 

 

最后

以上就是落后日记本为你收集整理的Verilog学习心得之五-----时钟分频器的全部内容,希望文章能够帮你解决Verilog学习心得之五-----时钟分频器所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(69)

评论列表共有 0 条评论

立即
投稿
返回
顶部