通常在面试中面试官可能会问到关于奇数分频的实现,比如三分频,五分频,七分频等,根据自己推敲和理解,并且总结规律,给出自己对于奇数分频的实现。首先,为了更好理解什么是三分频,五分频,七分频等,我们假设一个输入时钟的时钟周期为1s,则三分频后的输出时钟clk_out的时钟周期则为3s,同理,五分频的为5s,七分频的为7s,为了实现奇数分频,我们首先需要两个计数器,用来数时钟周期个数,一个以时钟上升沿为起点开始数,一个以时钟下降沿为起点开始数,并用这两个计数器来设计得到clk_s和clk_x,则clk_out就等于clk_s和clk_x相与,现在似乎难理解一点,我们先通过代码进行实现,并对波形进行查看就方便理解了
先以三分频为例,先定义两个计数器
上升沿计数器cnt_s如下:
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_s<=0;
end
else if(add_cnt_s)begin //add_cnt_s表示计数开始条件
if(end_cnt_s) //end_cnt_s表示计数结束条件
cnt_s<=0;
else
cnt_s<=cnt_s+1;
end
end
assign add_cnt_s=1; //这个让它一直计数
assign end_cnt_s=add_cnt_s && cnt_s==3-1;
下降沿计数器cnt_x如下:
always @(negedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_x<=0;
end
else if(add_cnt_x)begin //add_cnt_x表示计数开始条件
if(end_cnt_x) //end_cnt_x表示计数结束条件
cnt_x<=0;
else
cnt_x<=cnt_x+1;
end
end
assign add_cnt_x=1; //这个让它一直计数
assign end_cnt_x=add_cnt_x && cnt_x==3-1;
其总的设计代码如下:
module sanfenpin(clk,rst_n,clk_out);
input clk;
input rst_n;
output clk_out;
reg[3:0] cnt_s;
wire add_cnt_s;
wire end_cnt_s;
reg[3:0] cnt_x;
wire add_cnt_x;
wire end_cnt_x;
reg clk_s;
reg clk_x;
wire clk_out;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_s<=0;
end
else if(add_cnt_s)begin //add_cnt_s表示计数开始条件
if(end_cnt_s) //end_cnt_s表示计数结束条件
cnt_s<=0;
else
cnt_s<=cnt_s+1;
end
end
assign add_cnt_s=1; //这个让它一直计数
assign end_cnt_s=add_cnt_s && cnt_s==3-1;
always @(negedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_x<=0;
end
else if(add_cnt_x)begin //add_cnt_x表示计数开始条件
if(end_cnt_x) //end_cnt_x表示计数结束条件
cnt_x<=0;
else
cnt_x<=cnt_x+1;
end
end
assign add_cnt_x=1; //这个让它一直计数
assign end_cnt_x=add_cnt_x && cnt_x==3-1;
always @(posedge clk or negedge rst_n)begin //上升沿计数,设计clk_s
if(rst_n==1'b0)begin
clk_s<=0;
cnt_s<=0;
end
else if(add_cnt_s && cnt_s==1-1)begin
clk_s<=0;
end
else if (add_cnt_s &&cnt_s==2-1)begin
clk_s<=1;
end
end
always @(negedge clk or negedge rst_n)begin //下降沿计数,定义clk_x
if(rst_n==1'b0)begin
clk_x<=0;
cnt_x<=0;
end
else if(add_cnt_x && cnt_x==1-1)begin
clk_x<=0;
end
else if (add_cnt_x &&cnt_x==2-1)begin
clk_x<=1;
end
end
assign clk_out= clk_s & clk_x;
endmodule
输入时钟和复位信号,其测试代码如下:
module sanfenpin_tb;
parameter cycle=10;
reg clk;
reg rst_n;
wire clk_out;
sanfenpin uut(
.clk(clk),
.rst_n(rst_n),
.clk_out(clk_out)
);
initial begin
clk=0;
forever #(cycle/2) begin
clk=~clk;
end
end
initial begin
#1;
rst_n=0;
#(100*cycle);
rst_n=1;
end
endmodule
运行仿真,其波形如下:
从波行可以看出,clk_out的周期等于三个clk的周期,说明设计符合要求,对于五分频,测试代码不用变,我们只需要使两个计数器数五个时钟周期,并且使clk_s和clk_x过两个时钟周期后跳变,如下
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
clk_s<=0;
cnt_s<=0;
end
else if(add_cnt_s && cnt_s==1-1)begin
clk_s<=0;
end
else if (add_cnt_s &&cnt_s==3-1)begin //clk_s为0和1相隔两个时钟周期,clk_x也是如此
clk_s<=1;
end
end
always @(negedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
clk_x<=0;
cnt_x<=0;
end
else if(add_cnt_x && cnt_x==1-1)begin
clk_x<=0;
end
else if (add_cnt_x &&cnt_x==3-1)begin
clk_x<=1;
end
end
其波形图如下
同理七分频,则相隔三个时钟周期进行跳变,运行仿真后,其波形如下:
通过观察波形,说明设计符合要求,至此,可以总结出规律,N(为奇数)分频,需要定义两个计数器,分别以上升沿和下降沿为起始,计N个数,而clk_s和clk_x相隔(N-1)/2个clk周期后跳变,值得注意的是,上述分频的实现占空比都是百分之五十(高电平的占比),这也迎合大部分的设计要求,其次,随着分频数的增加,计数器的位宽也需要作出调整,至此,奇数分频的实现就总结完成