时钟信号的处理是FPGA开发中一个特色,由于不同模块之间需要不同的时钟进行控制。通过设计模块进行时钟分频是FPGA开发过程中的一个重要训练。本文介绍如何实现任意整数的分频器,分频的时钟保持50%占空比。本文时钟分频部分参考时钟分频设计
理论介绍
偶数分频:偶数分频相对简单,容易理解。通过计数器计数即可实现。如进行N倍偶数分频,那么通过时钟触发计数器计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,以此循环下去。
![偶数分频.png](//file.elecfans.com/web2/M00/1F/7A/pYYBAGGYL4aAOLU0AAAOSpCm0dc283.png)
奇数分频:如果要实现占空比为50%的奇数分频,不能同偶数分频一样计数记到一半的时候输出时钟翻转,那样得不到占空比50%的时钟。以待分频时钟CLk为例,如果以偶数分频的方法来做奇数分频,在CLK上触发,将得到不是50%占空比的一个时钟信号(正周期比负周期多一个时钟或者少一个时钟);但是如果在CLK下降沿也触发,又得到另外一个不是50%占空比的时钟信号,这连个时钟相位正好相差半个CLK时钟周期。通过这两个时钟信号进行逻辑运算我们可以巧妙地得到50%占空比的时钟。
总结如下:对于实现占空比为50%的N倍奇数分频,首先进行上升沿触发进行模N计数,计数选定到某一个值进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比非50%奇数n分频时钟。再同时进行下降沿触发的模N计数,到和上升沿触发输出时钟翻转选定值相同时,进行输出时钟翻转,同样经过(N-1)/2时,输出时钟再次翻转生成占空比非50%的奇数n分频四种。两个占空比非50%的n分频时钟进行逻辑运算(正周期多的相与,负周期多的相或),得到占空比为50%的奇数n分频时钟。
![奇数分频.png](//file.elecfans.com/web2/M00/1F/72/poYBAGGYL4iARg4dAAATnr9Hg4Q012.png)
Verilog模块设计
基于上述的分析,设计时钟分频模块如下:
module divide ( clk,rst_n,clkout);
input clk,rst_n;
output clkout;
parameter WIDTH = 3;
parameter N = 5;
reg [WIDTH-1:0] cnt_p,cnt_n;
reg clk_p,clk_n;
always @ (posedge clk or negedge rst_n )
begin
if(!rst_n)
cnt_p<=0;
else if (cnt_p==(N-1))
cnt_p<=0;
else cnt_p<=cnt_p+1;
end
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_p<=0;
else if (cnt_p<(N>>1))
clk_p<=0;
else
clk_p<=1;
end
always @ (negedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_n<=0;
else if (cnt_n==(N-1))
cnt_n<=0;
else cnt_n<=cnt_n+1;
end
always @ (negedge clk)
begin
if(!rst_n)
clk_n<=0;
else if (cnt_n<(N>>1))
clk_n<=0;
else
clk_n<=1;
end
assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p;
endmodule
结合板上LED灯,实现1Hz~8Hz的LED灯翻转,设计模块如下:
module clk_divider
(
input clk,
input rst_n,
output[7:0] led
);
wire clk1Hz,clk_div2,clk_div3,clk_div4,clk_div5,clk_div6,clk_div7,clk_div8;
divide
clk_1Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk1Hz)
);
divide
clk_2Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk_div2)
);
divide
clk_3Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk_div3)
);
divide
clk_4Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk_div4)
);
divide
clk_5Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk_div5)
);
divide
clk_6Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk_div6)
);
divide
clk_7Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk_div7)
);
divide
clk_8Hz(
.clk(clk),
.rst_n(rst_n),
.clkout(clk_div8)
);
assign led={clk1Hz,clk_div2,clk_div3,clk_div4,clk_div5,clk_div6,clk_div7,clk_div8};
endmodule
添加引脚约束如下
![流水灯约束.png](//file1.elecfans.com/web2/M00/B8/4B/wKgZomWDE7eADDXlAAIXqdMdc_U712.png)
实验的效果如下