5 半整数分频
设计思路
n为半整数时,用计数器无法实现占空比为50%的分频时钟,因为n=N+0.5时,新时钟在一个周期内高低电平都必须为(N/2+0.25)个原时钟,0.25个原时钟无法用计数器实现。
下面介绍简单的半整数分频,仅能实现1/n的占空比,虽不均匀,但适用性强且方便易写。
回顾奇数分频的实现,用占空比相同的两个时钟间隔半个原时钟周期,或操作后得到占空比为50%。这里的操作也类似,n为=N.5时,无法直接得到n分频时钟,但2n一定为整数,能很轻易地得到2n分频的时钟(这里未采用时钟翻转,而是时钟直接赋予高低电平,占空比为1/2n),调整两个2n分频时钟的间隔后进行或操作,即可得到占空比为1/2n的N.5分频时钟。
程序设计
`timescale 1ns/1ns
module Np5_div
#(
parameter n = 2.5
)
(
input wire clk,
input wire rstn,
output wire clk_out
);
reg [31:0] cnt;
reg clk_r1, clk_r2;
always @(posedge clk or negedge rstn) begin
if(~rstn)
cnt <=0;
else if(cnt==2*n-1)
cnt <=0;
else
cnt <=cnt + 1'b1;
end
//上升沿分频
always @(posedge clk or negedge rstn) begin
if(~rstn)
clk_r1 <=0;
else if(cnt==2*n-1)
clk_r1 <=1;
else
clk_r1 <=0; //别的是计数满足就翻转,没到就保持;这里技术满足就拉高,没到拉低。
end
//下降沿分频
always @(negedge clk or negedge rstn) begin
if(~rstn)
clk_r2 <=0;
else if(cnt==(2*n-1)/2)
clk_r2 <=1;
else
clk_r2 <=0;
end
assign clk_out =(clk_r1 | clk_r2);
endmodule
tb文件
`timescale 1ns/1ns
module tb_Np5_div();
localparam n = 4.5;
reg clk;
reg rstn;
wire clk_out;
//时钟
localparam T =10;
initial begin
clk =0;
forever #(T/2) clk = ~clk;
end
//赋值
initial begin
rstn =0;
repeat(4) @(posedge clk);
rstn =1;
#1000
$finish();
end
//例化
Np5_div #(
.n (n)
)
Np5_div_inst (
.clk (clk),
.rstn (rstn),
.clk_out (clk_out)
);
endmodule
波形仿真
100MHz时钟,1.5分频如下图。
2.5分频如下图。
3.5分频如下图。
4.5分频如下图。
6 小数分频
设计思路
小数/分数分频,可将A个原始时钟融合,输出为B个新时钟。clk_in × A = clk_out × B,即用A个原周期合成B个新周期。
以19/9分频为例,clk_in × 19/9 = clk_out → clk_in × 19 = clk_out × 9,即19个原周期合成9个新周期。具体而言,原时钟的每19个周期中,输出端应产生9个新时钟脉冲信号。分频系数19/9介于2~3之间,可以通过二分频和三分频混合的方式来实现。令需要x个二分频,y个三分频,x+y=9
;2x+3y=19
,解得x=8
,y=1
,即每组循环输出8个二分频和1个三分频,一组得到9个19/9分频。
再如8.7分频,clk_in × 8.7 = clk_out → clk_in × 87 = clk_out × 10,即87个原周期合成10个新周期。分频系数8.7介于8~9之间,可以通过八分频和九分频混合的方式来实现。令需要x个八分频,y个九分频,x+y=10
;8x+9y=87
,解得x=3
,y=7
,即每组循环输出3个八分频和7个九分频,一组得到10个8.7分频。
这里暂不考虑均匀插入,只是简单地先后两份输出。3个八分频与7个九分频一组,考虑分频转折点24,当主计数器为0~23时输出八分频,为24~87时输出九分频,一组整体而言便是8.7分频。
程序设计
`timescale 1ns/1ns
module frac_div
#(
parameter n = 19/9
)
(
input wire clk,
input wire rstn,
output wire clk_out
);
//8.7分频,x+y=10;8x+9y=87,解得x=3,y=7。3个八分频,然后7个九分频。切换点是24
parameter M =87;
parameter change =24; //分频转变点。0~23,24~86
parameter div_a =8;
parameter div_b =9;
reg [$clog2(M)-1:0] cnt; //主计数器,计数0~86
reg [$clog2(div_a)-1:0] cnt_a; //8分频计数器,主计数器0~23时,进行8分频,循环计数0~7
reg [$clog2(div_b)-1:0] cnt_b; //9分频计数器,主计数器24~86时,进行9分频,循环计数0~8
reg clk_a;
reg clk_b1, clk_b2;
wire clk_b;
//——————————————————————————————主计数器——————————————————————————————
always @(posedge clk or negedge rstn) begin
if(~rstn)
cnt <=0;
else if(cnt==M-1)
cnt <=0;
else
cnt <=cnt + 1'b1;
end
//0~change-1计数cnt_a,change~M-1计数cnt_b
//a分频计数
always @(posedge clk or negedge rstn) begin
if(~rstn)
cnt_a <=0;
else if(cnt <= change-1)begin
if(cnt_a==div_a-1)
cnt_a <=0;
else
cnt_a <=cnt_a + 1'b1;
end
//else保持省略
end
//b分频计数 0~change-1计数cnt_a,change~M-1计数cnt_b
always @(posedge clk or negedge rstn) begin
if(~rstn)
cnt_b <=0;
else if(cnt > change-1)begin
if(cnt==M-1 || cnt_b==div_b-1)
cnt_b <=0;
else
cnt_b <=cnt_b + 1'b1;
end
//else保持省略
end
//——————————————————————————————八分频——————————————————————————————
always @(posedge clk or negedge rstn) begin
if(~rstn)
clk_a <=0;
else if(cnt_a==div_a/2-1 || cnt_a==div_a-1)
clk_a <=~clk_a;
end
//——————————————————————————————九分频——————————————————————————————
//上升沿
always @(posedge clk or negedge rstn) begin
if(~rstn)
clk_b1 <=0;
else if(cnt_b==(div_b-1)/2 || cnt_b==div_b-1)
clk_b1 <=~clk_b1;
end
//下降沿
always @(negedge clk or negedge rstn) begin
if(~rstn)
clk_b2 <=0;
else if(cnt_b==(div_b-1)/2 || cnt_b==div_b-1)
clk_b2 <=~clk_b2;
end
assign clk_b =(clk_b1 | clk_b2);
//——————————————————————————————选择输出——————————————————————————————
assign clk_out =(cnt<=change-1)? clk_a:clk_b;
endmodule
tb文件
`timescale 1ns/1ns
`include "frac_div.v"
module tb_frac_div();
localparam n = 19/9;
reg clk;
reg rstn;
wire clk_out;
initial begin
$dumpfile("frac_div.vcd");
$dumpvars();
end
//时钟
localparam T =10;
initial begin
clk =0;
forever #(T/2) clk = ~clk;
end
//赋值
initial begin
rstn =0;
repeat(4) @(posedge clk);
rstn =1;
#3000
$finish;
end
//例化
frac_div # (
.n(n)
)
frac_div_inst (
.clk (clk),
.rstn (rstn),
.clk_out (clk_out)
);
endmodule
波形仿真
如图100MHz进行8.7分频,每组循环输出3个八分频和7个九分频,一组得到10个8.7分频。