1.偶数分频
所谓分频,就是将时钟的频率分下来,比如50MHZ的时钟,二分频就成了25MHZ的时钟,四分频就成了12.5MHZ的时钟,总而言之,N分频就是把50MHZ的时钟分成N分,我取一份;
那么此处的偶数分频,是最简单的分频。举个例子,以100分频为例,我们需要用100个原始的时钟周期T,作为我们分频后新的时钟周期T1,也就是T1 = 100T;那么时钟的占空比都是50%,所以很明显,在50T的时候翻转时钟就行;
利用计数器可以对原始时钟的周期个数的进行计数,在计数到50T,也就是49的时候,新时钟进行反转,得到100分频时钟;
进而得到规律:实现N分频(N为偶数),只需要在计数到N/2-1时翻转新的时钟信号即可;
下面是一个10分频的代码,因此计数到4时时钟翻转:
module div_10
(
input clk,
input rst_n,
output reg clk_div
);
//参数
parameter N = 4'd10;
//内部信号
reg [3:0] cnt;
//功能块
always@(posedge clk or negedge rst_n)begin
if (!rst_n)begin
cnt <= 0;
end
else if(cnt == N - 1 ) begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
always@(posedge clk or negedge rst_n)begin
if (!rst_n) begin
clk_div <= 0;
end
else if (cnt <= (N/2)-1) begin
clk_div <= 1;
end
else begin
clk_div <= 0;
end
end
endmodule
测试代码如下;
`timescale 1 ns/1 ns //时间标尺 时间单位/时间精度
module tb_div_10();
//例化的v模块的输入信号
//输入用reg
reg clk;
reg rst_n;
//例化的v模块的输出信号
//输出用wire
wire clk_div;
//时钟周期,单位为ns
parameter CYCLE = 20;
//生成本地时钟
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
//产生复位信号
initial begin
rst_n = 1;
#2;
rst_n = 0;
#2
rst_n = 1;
end
//待测试的模块例化
div_10 u1
(
.clk (clk),
.rst_n (rst_n),
.clk_div (clk_div)
);
//可能还会有其他输入信号赋值
//此例子没有
endmodule
仿真结果;
2.奇数分频
奇数分频比偶数分频要复杂一点,奇数分频的翻转点在0.5个时钟处,上升沿并不能检测到此处,因此我们需要用到上升沿计数以及下降沿计数;
一个时钟,然后两个计数器分别采样上升沿和下降沿,然后利用偶数分频的办法,得到两个中间时钟,这两个时钟周期为2N+1,N个周期的高电平,N+1个周期的低电平,然后利用两个中间时钟进行相或操作得到奇数分频
做法:对于一个2N+1分频,用两个计数器分别采样上升沿和下降沿个数,计数到2N+1(代码中是2N,因为计算机从0开始数),用两个计数器产生两个时钟,在N+1和2N+1计数处翻转,得到的两个时钟相或,得出2N+1分频时钟
下面我们做一个5分频设计:此时N=2,代码中在N以及2N处对两个时钟反转,实际是在N+1和2N+1处翻转
module div_5
(
input clk,
input rst_n,
output wire clk_div
);
//参数
parameter N = 2'd2;
//内部信号
reg [2:0] cnt_pose;
reg [2:0] cnt_nege;
reg clk_pose;
reg clk_nege;
//功能块
always@(posedge clk or negedge rst_n)begin // 对上升沿计数
if(!rst_n)
cnt_pose <= 0;
else if(cnt_pose == 2*N)
cnt_pose <= 0;
else
cnt_pose <= cnt_pose + 1;
end
always@(posedge clk or negedge rst_n)begin // 中间时钟clk_pose
if(!rst_n)
clk_pose<=0;
else if(cnt_pose == N||cnt_pose == 2*N)
clk_pose <= ~clk_pose;
else
clk_pose <= clk_pose;
end
always@(negedge clk or negedge rst_n)begin // 对下降沿计数
if(!rst_n)
cnt_nege <= 0;
else if(cnt_nege == 2*N)
cnt_nege <= 0;
else
cnt_nege <= cnt_nege + 1;
end
always@(negedge clk or negedge rst_n)begin // 中间时钟clk_nege
if(!rst_n)
clk_nege <= 0;
else if(cnt_nege == N||cnt_nege == 2*N)
clk_nege <= ~clk_nege;
else
clk_nege <= clk_nege;
end
assign clk_div = clk_pose|clk_nege; // 2N+1分频时钟输出
endmodule
测试文件:
`timescale 1 ns/1 ns //时间标尺 时间单位/时间精度
module tb_div_5();
//例化的v模块的输入信号
//输入用reg
reg clk;
reg rst_n;
//例化的v模块的输出信号
//输出用wire
wire clk_div;
//时钟周期,单位为ns
parameter CYCLE = 20;
//生成本地时钟
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
//产生复位信号
initial begin
rst_n = 1;
#2;
rst_n = 0;
#2
rst_n = 1;
end
//待测试的模块例化
div_5 u1
(
.clk (clk),
.rst_n (rst_n),
.clk_div (clk_div)
);
//可能还会有其他输入信号赋值
//此例子没有
endmodule
仿真结果: