目录
任意分频后面再写吧
三分频
3 分频的本质是我们需要在每次 1.5 倍的时钟周期的时候实现 3 分频寄存器的翻转,但是我们无法直接实现 1.5 倍的分频。因此采取分别采取 2 个计数器 pos_cnt 和 neg_cnt,分别对上升沿和下降沿计数。计数周期是 0-1-2,共计 3 个时钟周期。
我们取 pos_cnt == 2'd1 的时候 div_pos输出高电平,neg_cnt == 2'd1 的时候 div_neg输出高电平。
由于 div_pos和 div_neg输出 1 个时钟的高电平,但是相位相差 180°,因此只要执行 div3_o = div_pos|div_neg运算,就能实现 1.5 倍周期的输出高电平,那么剩余的 1.5 倍源时钟周期就是输出低电平了。
时序图分析:
三分频verilog代码
module clk_divider
(
input sys_clk,
input sys_rst_n,
output clk_div_o
);
reg [1:0] pos_cnt,neg_cnt;
reg div_pos,div_neg;
//上升沿计数器
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
pos_cnt <= 0;
else if(pos_cnt == 2'd2) //
pos_cnt <= 0;
else
pos_cnt <= pos_cnt + 1'b1;
end
//下降沿计数器
always@(negedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
neg_cnt <= 0;
else if(neg_cnt == 2'd2)
neg_cnt <= 0;
else
neg_cnt <= neg_cnt + 1'b1;
end
//上升沿电平变换
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
div_pos <= 0;
else if(pos_cnt < 2'd1)
div_pos <= 1;
else
div_pos <= 0;
end
//下降沿电平变换
always@(negedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
div_neg <= 0;
else if(neg_cnt < 2'd1 )
div_neg <= 1;
else
div_neg <= 0;
end
//输出相或
assign clk_div_o = div_pos | div_neg;
endmodule
Testbench
`timescale 1ns/1ns
module clk_div_tb();
reg sys_clk;
reg sys_rst_n;
wire clk_div_o;
parameter T = 20;
always #(T/2) sys_clk = ~sys_clk;
clk_divider clk_divider_inst
(
.sys_clk(sys_clk) ,
.sys_rst_n(sys_rst_n) ,
.clk_div_o(clk_div_o)
);
initial begin
sys_clk = 0;
sys_rst_n = 0;
#50;
sys_rst_n = 1;
end
endmodule
仿真示意图 ,clk_div_o 高低电平各占1.5个时钟周期
五分频
三分频,每1.5个时钟周期就要翻转一次,因此我们通过时钟上升沿构造低电平占1个时钟周期,高电平占2个时钟周期的信号,再通过时钟的下降沿产生相同的信号,这相当与把原信号右移了半个时钟周期,相与后高电平被削掉了半个周期,低电平添了半个周期,就产生了1.5个时钟周期翻转一次的效果。
五分频类似。
由此猜测11分频可以由上升沿构造低电平占5个时钟周期,高电平占6个时钟周期的信号产生。
五分频的思想是用一个上升沿的计数器计 0-4,上升沿和下降沿分别计数,高电平2个周期,低电平3个周期,2者相与
Verilog实现
module clk_div5
(
input sys_clk,
input sys_rst_n,
output clk_div_o
);
reg [2:0] clk_cnt;
reg div_pos,div_neg;
//上升沿计数器 clk_cnt=0-4
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
clk_cnt <= 0;
else if(clk_cnt == 3'd4) //
clk_cnt <= 0;
else
clk_cnt <= clk_cnt + 1'b1;
end
//上升沿计数高电平2个周期 低电平3个周期
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
div_pos <= 1'b1;
else if(clk_cnt < 3'd3)
div_pos <= 1'b1;
else
div_pos <= 0;
end
//下降沿计数高电平2个周期 低电平3个周期
always@(negedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
div_neg <= 1'b1;
else if(clk_cnt < 3'd3 )
div_neg <= 1'b1;
else
div_neg <= 0;
end
//输出相与
assign clk_div_o = div_pos & div_neg;
endmodule
Tb 还用上面的
任意分频等后面再写吧