时钟分频也是笔试题里面经常出现的,(我已经遇到过了),看完这一篇,分分钟掌握!
目录
偶数分频
D触发器级联法
计数器法
奇数分频
占空比50% 的奇数分频
占空比无要求的奇数分频
任意小数分频
如上图输入给clk,输出将其变成周期为2倍的clk_out2, 将其变成周期为4倍的clk_out4,将其变成周期为8倍的clk_out8,占空比为50%
对于偶数分频电路,在不考虑时钟同步时钟延迟的问题时,直接使用D触发器级联来实现:关键在于,上升沿才能触发翻转,但是一个周期只有一个上升沿,因此周期翻倍
`timescale 1ns/1ns
module even_div
(
input wire rst ,
input wire clk_in,
output wire clk_out2,
output wire clk_out4,
output wire clk_out8
);
reg clk_out2_r, clk_out4_r, clk_out8_r;
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_out2_r <= 0;
else
clk_out2_r <= ~clk_out2_r;
end
always@(posedge clk_out2 or negedge rst) begin
if(~rst)
clk_out4_r <= 0;
else
clk_out4_r <= ~clk_out4_r;
end
always@(posedge clk_out4 or negedge rst) begin
if(~rst)
clk_out8_r <= 0;
else
clk_out8_r <= ~clk_out8_r;
end
assign clk_out2 = clk_out2_r;
assign clk_out4 = clk_out4_r;
assign clk_out8 = clk_out8_r;
endmodule
2、4、8恰好是2的次方,可构造一个3位计数器,依靠第0位,第1位,第2位的变化速度来实现:
2分频的输出=cnt第0位(由于计数器在clk=高电平时才+1,因此本身就是2倍的周期)
4分频输出=cnt第1位
8分频输出=cnt第2位
eg 4分频:000 001 010 011 100 101 110 111 000
`timescale 1ns/1ns
module even_div
(
input wire rst ,
input wire clk_in,
output wire clk_out2,
output wire clk_out4,
output wire clk_out8
);
reg [2:0]cnt;
always@(posedge clk_in or negedge rst)
if(!rst)
cnt <= 3'b111;//初始赋全1
else
cnt <= cnt+1;
assign clk_out2 = ~cnt[0];//根据波形,一开始全为高电平
assign clk_out4 = ~cnt[1];
assign clk_out8 = ~cnt[2];
endmodule
对于奇数分频电路,主要难点在于50%占空比的实现。单触发沿在奇数分频中是没有办法实现50%占空比的,因此需要考虑使用双边沿加组合逻辑实现50%占空比
设置计数器,计数器从0→6,当计数器==3,上升沿触发得到clk_pos,下降沿触发得到clk_neg,
而输出的7分频clk,上升沿在clk_neg触发,下降沿在clk_pos触发,是clk_neg和clk_pos进行或运算的结果
根据这个思路,我们可以得到任意奇数分频,占空比为50%的输出,修改N值即可,代码如下:
`timescale 1ns/1ns
module odo_div_or
#(parameter N = 7)
(
input wire rst ,
input wire clk_in,
output wire clk_out7
);
reg [3:0] cnt ;
always @(posedge clk_in or negedge rst) begin
if (!rst) begin
cnt <= 'b0 ;
end
else if (cnt == N-1) begin
cnt <= 'b0 ;
end
else begin
cnt <= cnt + 1'b1 ;
end
end
reg clkp ;
always @(posedge clk_in or negedge rst) begin
if (!rst) begin
clkp <= 1'b0 ;
end
else if (cnt == (N>>1)) begin
clkp <= 1 ;
end
else if (cnt == N-1) begin
clkp <= 0 ;
end
end
reg clkn ;
always @(negedge clk_in or negedge rst) begin
if (!rst) begin
clkn <= 1'b0 ;
end
else if (cnt == (N>>1) ) begin
clkn <= 1 ;
end
else if (cnt == N-1) begin
clkn <= 0 ;
end
end
assign clk_out7 = clkp | clkn ;
endmodule
实现一个5分频clk,占空比可修改
由于一个cnt其实=2个clk_in ,所以在占空比不要求的情况下,即使是奇数分频也=一个偶数,我们可以把这个偶数分成2个偶数的和,(例如5分频相当于10clk_in,10=4+6,可以4clk_in低电平,6clk_in高电平)(而要求占空比的时候,10=5+5,需要参考上面的做法)
一个完整的clk周期要包含5个clk_in,但是占空比不要求,那么设置一个计数器cnt
,计数范围0-4,每个clk_in
周期加1。当计数器数值在0~1时,clk_out5==1
;当计数器数值在2~4时,clk_out5==0
。这样就实现了周期为5、占空比为3/5 的clk_out5
`timescale 1ns/1ns
module odd_div (
input wire rst ,
input wire clk_in,
output wire clk_out5
);
reg [2:0] cnt;
reg clk_out5_r;
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_out5_r <= 0;
else
clk_out5_r <=1;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
cnt <= 0;
else
cnt <= cnt==4? 0: cnt+1;
end
assign clk_out5 = clk_out5_r;
endmodule
小数分频器是分频器中最难的一种,而且不能像整数分频那样得到均匀且占空比为50%的分频输出
`timescale 1ns/1ns
module div_M_N(
input wire clk_in,
input wire rst,
output wire clk_out
);
parameter M_N = 8'd87;
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
reg [3:0] clk_cnt;
reg [6:0] cyc_cnt;
reg div_flag;
reg clk_out_r;
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_cnt <= 0;
else if(~div_flag)
clk_cnt <= clk_cnt==(div_e-1)? 0: clk_cnt+1;
else
clk_cnt <= clk_cnt==(div_o-1)? 0: clk_cnt+1;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
cyc_cnt <= 0;
else
cyc_cnt <= cyc_cnt==(M_N-1)? 0: cyc_cnt+1;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
div_flag <= 0;
else
div_flag <= cyc_cnt==(M_N-1)||cyc_cnt==(c89-1)? ~div_flag: div_flag;
end
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_out_r <= 0;
else if(~div_flag)
clk_out_r <= clk_cnt<=((div_e>>2)+1);
else
clk_out_r <= clk_cnt<=((div_o>>2)+1);
end
assign clk_out = clk_out_r;
//*************code***********//
endmodule