【Verilog HDL实践】奇数、半整数分频实现
使用芯片:Altera Cyclone® IV EP4CE22F17C6N FPGA
开发工具:Quartus Ⅱ
开发项目:七、设计奇数分频器、半整数分频器。
参考文章Verilog 时钟分频
奇数分频器分析
奇数分频可通过两个通过不同沿触发产生的偶数分频器或、与、异或产生
例如3分频:
clk | 01 01 01 01 01 01 |
---|---|
timer1 | 11 00 00 11 00 00 |
timer2 | 01 10 00 01 10 00 |
output | 11 10 00 11 10 00 |
其中,timer1为上升沿触发,可以看到它每次在上升沿改变数值;timer2为下降沿触发;output为相或的结果。
如果想用相与, 可将timer的电平反转。
特点分析:
timer2落后timer1一个时钟电平长度,即半个时钟周期。
timer1和timer2周期长度与分频后结果一致,只是占空比不同
当使用相或时,timer1周期内处于低电平的长度等于分频数-1。因为timer2刚好落后一个小电平长度,这样相或即等效于原有基础+1。
代码展示
module Divider(clk, divider_3);
input clk;
output divider_3;
parameter cycle_one = 2'b11; //3分频
parameter duty_zero = (cycle_one+1)/2; //电平为低周期为2 则低:高=2:1
reg[3:0] timer1=4'b0, timer2=4'b0;
reg timer_out1=1'b0, timer_out2=1'b1;
assign divider_3 = timer_out1|timer_out2;
always@(posedge clk) begin
timer1 <= timer1+1;
if(timer1 >= cycle_one-1)
timer1 <= 4'b0;
if(timer1 < duty_zero)
timer_out1 <= 1'b0;
else
timer_out1 <= 1'b1;
end
always@(negedge clk) begin
if(timer2 < cycle_one-1)
timer2 <= timer2+1;
else
timer2 <= 4'b0;
if(timer2 < duty_zero)
timer_out2 <= 1'b0;
else
timer_out2 <= 1'b1;
end
endmodule
我看过一些其他人写的代码,如上边推荐链接内的代码,他们只用了一个计数器,综合效果可能更佳。(当时没想到 唉)
时序测试
其中第一行为输入时钟源
第二行为三分频输出
第三行为其中一个计数器的电平变化,可以看到 高电平:低电平=1:2。
半整数分频器分析
利用时钟的双边沿逻辑,可以对时钟进行半整数的分频。但是无论怎么调整,半整数分频的占空比不可能是 50%。
那该怎么办呢?可以参考一下最前边链接里的文章(哭,我没有自己的见解
特点分析:
只需要两个定时器,定时器在2*分频倍数周期内可分为两个阶段。
前半周期 timer1优先timer2一个电平,后半周期落后一个电平。
代码展示
module Half_Divider(rstn, clk, clk_div9p5);
input rstn, clk;
output clk_div9p5;
parameter MUL2_DIV_CLK = 5;
parameter DIV_HIGH = (MUL2_DIV_CLK>6)?(MUL2_DIV_CLK-3)/4:1; //最小为2.5
reg [4:0] cnt = 5'b0;
reg clk_ave_r ;
reg clk_adjust_r ;
assign clk_div9p5 = clk_adjust_r | clk_ave_r;
always @(posedge clk or negedge rstn) begin
if (!rstn)
cnt <= 'b0 ;
else if (cnt == MUL2_DIV_CLK-1)
cnt <= 'b0 ;
else
cnt <= cnt + 1'b1 ;
end
always @(posedge clk or negedge rstn) begin
if (!rstn)
clk_ave_r <= 1'b0 ;
else if (cnt >= 0 & cnt <= DIV_HIGH-1)
clk_ave_r <= 1 ;
else if (cnt >= (MUL2_DIV_CLK/2+1) & cnt <= (MUL2_DIV_CLK/2+1)+DIV_HIGH-1)
clk_ave_r <= 1 ;
else
clk_ave_r <= 0 ;
end
always @(negedge clk or negedge rstn) begin
if (!rstn)
clk_adjust_r <= 1'b0 ;
else if (cnt >= 1 & cnt <= DIV_HIGH)
clk_adjust_r <= 1 ;
else if (cnt >= (MUL2_DIV_CLK/2+1) & cnt <= (MUL2_DIV_CLK/2+1)+DIV_HIGH-1)
clk_adjust_r <= 1 ;
else
clk_adjust_r <= 0 ;
end
endmodule
这份代码是仿照上边链接写的,当时以为3.5分频可以实现等占空比,想了想觉得 绝无可能 ,嗯,然后就去网上转了一圈,得思路,略改之。
时序测试
正如之前所说的,它并不是等占空比的。