FPGA-分频器
当给你一个时钟,你觉得频率太快了,想进行就分频,就会使用到我们的分频器。非常简单且实用,且写的无聊。
写给出总体代码
module div_frequency(
input clk_i,
input rst_n_i,
output div2_o,
output div3_o,
output div4_o,
output div8_o
);
reg div2_o_r;
always@(posedge clk_i or negedge rst_n_i)
begin
if(!rst_n_i)
div2_o_r<=1’b0;
else
div2_o_r<=~div2_o_r;
end
reg [1:0] div_cnt1;
always@(posedge clk_i or negedge rst_n_i)
begin
if(!rst_n_i)
div_cnt1<=2’b00;
else
div_cnt1<=div_cnt1+1’b1;
end
reg div4_o_r;
reg div8_o_r;
always@(posedge clk_i or negedge rst_n_i)
begin
if(!rst_n_i)
div4_o_r<=1’b0;
else if(div_cnt12’b00 || div_cnt12’b10)
div4_o_r<=~div4_o_r;
else
div4_o_r<=div4_o_r;
end
always@(posedge clk_i or negedge rst_n_i)
begin
if(!rst_n_i)
div8_o_r<=1’b0;
else if(div_cnt1==2’b00)
div8_o_r<=~div8_o_r;
else
div8_o_r<=div8_o_r;
end
reg [1:0] pos_cnt;
reg [1:0] neg_cnt;
always@(posedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
pos_cnt<=2’b00;
else if(pos_cnt==2’d2)
pos_cnt<=2’b00;
else
pos_cnt<=pos_cnt+1’b1;
end
always@(negedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
neg_cnt<=2’b00;
else if(neg_cnt==2’d2)
neg_cnt<=2’b00;
else
neg_cnt<=neg_cnt+1’b1;
end
reg div3_o_r0;
reg div3_o_r1;
always@(posedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
div3_o_r0<=1’b0;
else if(pos_cnt<2’d1)
div3_o_r0<=1’b1;
else
div3_o_r0<=1’b0;
end
always@(negedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
div3_o_r1<=1’b0;
else if(neg_cnt<2’d1)
div3_o_r1<=1’b1;
else
div3_o_r1<=1’b0;
end
reg div2hz_o_r;
assign div2_o=div2_o_r;
assign div3_o=div3_o_r0 | div3_o_r1;
assign div4_o=div4_o_r;
assign div8_o=div8_o_r;
endmodule
一,2分频部分
reg div2_o_r;
always@(posedge clk_i or negedge rst_n_i)
begin
if(!rst_n_i)
div2_o_r<=1’b0;
else
div2_o_r<=~div2_o_r;
end
我们设输入时钟的周期为T,
由上面代码可知,每当输入时钟上升沿的时候,我们就会翻转。输入时钟一个周期只有一个上升沿,那么也就意味着2分频高低电平持续时间是一个输入时钟周期T,则2分频的周期就是2T。达到了分频的效果。
(明明很简单,写的却很罗里吧嗦,还没图
二,四分频
有了上面2分频思想,四分频不是有手就行
我们只需要将always@(posedge clk_i or negedge rst_n_i),这个里面 clk_i换成我们已经写好的2分频,四分频就出来了。那八分频不也简单的狠。
但是如果每次都那么一个一个的写,不是很麻烦吗
那么我就加个计数器
reg [1:0] div_cnt1;
always@(posedge clk_i or negedge rst_n_i)
begin
if(!rst_n_i)
div_cnt1<=2’b00;
else
div_cnt1<=div_cnt1+1’b1;
end
reg div4_o_r;
always@(posedge clk_i or negedge rst_n_i)
begin
if(!rst_n_i)
div4_o_r<=1’b0;
else if(div_cnt12’b00 || div_cnt12’b10)
div4_o_r<=~div4_o_r;
else
div4_o_r<=div4_o_r;
end
每当输入时钟上升沿,计数器开始计数,也就是每过T,我们开始计数,没过2T我们来翻转电平。那么周期为4T。那么
其他偶数分频不是有手就行。
三,奇数分频
我们以3分频为例,为什么呢?(因为上面写了)
reg [1:0] pos_cnt;
reg [1:0] neg_cnt;
always@(posedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
pos_cnt<=2’b00;
else if(pos_cnt==2’d2)
pos_cnt<=2’b00;
else
pos_cnt<=pos_cnt+1’b1;
end
always@(negedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
neg_cnt<=2’b00;
else if(neg_cnt==2’d2)
neg_cnt<=2’b00;
else
neg_cnt<=neg_cnt+1’b1;
end
reg div3_o_r0;
reg div3_o_r1;
always@(posedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
div3_o_r0<=1’b0;
else if(pos_cnt<2’d1)
div3_o_r0<=1’b1;
else
div3_o_r0<=1’b0;
end
always@(negedge div2_o_r or negedge rst_n_i)
begin
if(!rst_n_i)
div3_o_r1<=1’b0;
else if(neg_cnt<2’d1)
div3_o_r1<=1’b1;
else
div3_o_r1<=1’b0;
end
assign div3_o=div3_o_r0 | div3_o_r1;
看了代码,我们三分频是基于2分频时钟,有两个计时器 pos_cnt;neg_cnt;
由代码我们可以看出,他们分别从二分频的上升沿和下降沿开始从0到2计数(显然时间间隔为T)
div3_o_r0 和 div3_o_r1在pos_cnt;neg_cnt为0的时刻为1,在1,2时间为0。
则div3_o当出现0时为1,无0则为1
从0计数到2,时间为6T,则每个数字为持续时间为2T
我们将0用00计,则每个数字持续时间为T
pos_cnt | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 0 | 1 | 1 | 2 | 2 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
neg_cnt | 2 | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 0 | 1 | 1 | 2 |
div3_o | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 |
(为什么不画个图?显然不会,而且图多了,反而不好看)
显然其周期为6T,是对2分频时钟进行三分频。(以此内推)