1.偶分频
占空比,一个周期内,高电平时间在整个周期时间的占比。
D触发器
2分频
使用一个D触发器,把输出Q的取反,作为输入,实现电平的翻转。因为T0时刻,Q反传入输入D,需要等下一个时钟上升沿T1,才会传到输出,所以实现了2分频。
4分频
使用两个D触发器串联,以第一个D触发器的输出Q,作为第二个触发器的时钟。
verilog代码如下:
module d_div2_4(
input clk,
input rst_n,
output clk_div2,
output clk_div4);
reg reg2;
reg reg4;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
reg1 <= 1'b0;
end
else begin
reg2 <= ~reg2;
end
end
always @(posedge reg1 or negedge rst_n) begin
if(!rst_n) begin
reg4 <= 1'b0;
end
else
reg4 <= ~reg4;
end
assign clk_div2 = reg2;
assign clk_div4 = reg4;
endmodule
仿真代码如下:
module tb();
reg clk ;
reg rst_n ;
wire clk_div2;
wire clk_div4;
parameter CLOCK_CYCLE = 20;
d_div2_4 DUT(
.clk (clk ),
.rst_n (rst_n ),
.clk_div2 (clk_div2 ),
.clk_div4 (clk_div4 )
);
initial clk = 1'b0;
always #(CLOCK_CYCLE/2) clk = ~clk;
initial begin
rst_n = 1'b1;
#(CLOCK_CYCLE*2);
rst_n = 1'b0;
#(CLOCK_CYCLE*2);
rst_n = 1'b1;
#(CLOCK_CYCLE*50);
$finish();
end
initial begin
$fsdbDumpfile();
$fsdbDumpvars;
end
endmodule
波形如下:
- 实现2 分频和4 分频
计数器
N(N为偶数)分频,在(N/2)- 1翻转。偶分频的占空比都为50%。
使用计数器实现6分频。
verilog代码如下:
module counter_div_6(
input clk,
input rst_n,
output clk_div_6);
parameter a = 6;
reg [3:0] counter;
reg clk_div;
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
counter <= 0;
clk_div <= 0;
end
else begin
if(counter == (a/2 -1)) begin
clk_div <= ~clk_div;
counter <= 0;
end
else
counter++;
end
end
assign clk_div_6 = clk_div;
endmodule
仿真代码如下:
module tb();
reg clk ;
reg rst_n ;
wire clk_div2;
wire clk_div_6 ;
parameter CLOCK_CYCLE = 20;
counter_div_6 DUT(
.clk (clk ),
.rst_n (rst_n ),
.clk_div_6 (clk_div_6 )
);
initial clk = 1'b0;
always #(CLOCK_CYCLE/2) clk = ~clk;
initial begin
rst_n = 1'b1;
#(CLOCK_CYCLE*2);
rst_n = 1'b0;
#(CLOCK_CYCLE*2);
rst_n = 1'b1;
#(CLOCK_CYCLE*50);
$finish();
end
initial begin
$fsdbDumpfile();
$fsdbDumpvars;
end
endmodule
波形如下:
2.奇分频
2.1占空比50%
计数器
① 设计2个分别用上升、下降沿触发的计数器
② 利用上升、下降沿计数器生成两个分频时钟clk_p和clk_n
③ 利用clk_p和clk_n通过逻辑运算 “与” 生成占空比为50%的分频时钟
verilog代码如下:
module div7_5_5(
input clk,
input rst_n,
output clk_div7
);
reg [3:0] counter1;
reg [3:0] counter2;
reg clk_reg1;
reg clk_reg2;
parameter D = 7;
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
clk_reg1 <= 0;
end
else begin
if(counter1 == 6) begin
counter1 <= 0;
clk_reg1 <= ~clk_reg1;
end
else begin
if(counter1 == 2) begin
clk_reg1 <= ~clk_reg1;
end
end
end
end
always @(negedge clk or negedge rst_n) begin
if(~rst_n) begin
clk_reg2 <= 0;
end
else begin
if(counter2 == 6) begin
counter2 <= 0;
clk_reg2 <= ~clk_reg2;
end
else begin
if(counter2 == 2) begin
clk_reg2 <= ~clk_reg2;
end
end
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
counter1 <= 0;
else
counter1++;
end
always @(negedge clk or negedge rst_n) begin
if(~rst_n)
counter2 <= 0;
else
counter2++;
end
assign clk_div7 = clk_reg1 & clk_reg2;
endmodule
仿真代码如下:
module tb();
reg clk ;
reg rst_n ;
wire clk_div7;
parameter CLOCK_CYCLE = 20;
div7_5_5 DUT(
.clk (clk ),
.rst_n (rst_n),
.clk_div7 (clk_div7)
);
initial clk = 1'b0;
always #(CLOCK_CYCLE/2) clk = ~clk;
initial begin
rst_n = 1'b1;
#(CLOCK_CYCLE*2);
rst_n = 1'b0;
#(CLOCK_CYCLE*2);
rst_n = 1'b1;
#(CLOCK_CYCLE*50);
$finish();
end
initial begin
$fsdbDumpfile();
$fsdbDumpvars;
end
endmodule
波形如下:
2.2占空比非50%
计数器
源时钟sclk,目标时钟dclk。以7分频,占空比为4/7为例。以sclk的一个period为最小计数单位。即dclk的一个clock period中,电平低占了3个 sclk 时钟周期,高电平占4个 sclk 时钟周期。如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o5h5szSV-1651066744111)(C:/Users/61582/Documents/Typora/tmpC74.png)]
只要当dclk在counter = 2 时,dclk翻转一次,当counter计数到6时,再翻转一次,同时counter重新计数(counter = 0)即可得到我们需要的波形。
verilog代码如下:
module div_7(
input clk,
input rst_n,
output clk_div7
);
reg [3:0] counter;
reg clk_reg;
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
clk_reg <= 0;
end
else begin
if(counter == 6) begin
counter <= 0;
clk_reg <= ~clk_reg;
end
else begin
if(counter == 2) begin
clk_reg <= ~clk_reg;
end
end
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
counter <= 0;
else
counter++;
end
assign clk_div7 = clk_reg;
endmodule
仿真代码如下:
module tb();
reg clk;
reg rst_n;
wire clk_div7;
parameter CLOCK_CYCLE = 20;
div_7 DUT(
.clk (clk ),
.rst_n (rst_n),
.clk_div7 (clk_div7)
);
initial clk = 1'b0;
always #(CLOCK_CYCLE/2) clk = ~clk;
initial begin
rst_n = 1'b1;
#(CLOCK_CYCLE*2);
rst_n = 1'b0;
#(CLOCK_CYCLE*2);
rst_n = 1'b1;
#(CLOCK_CYCLE*50);
$finish();
end
//generate wave
initial begin
$fsdbDumpfile();
$fsdbDumpvars;
end
endmodule
波形如下:
- 复位后,clk_div7为0,所clk_div7的波形是以低电平开始。
- 光标处,采样到的counter值为6,而不是0;
N(N为奇数)分频电路,第一次dclk的翻转时间取决于占空比,第二次翻转为当counter == N-1时。
如是3分频电路,占空比为(1/3),则,当counter == 1时dclk翻转一次,counter == 2时dclk翻转一次。
状态机
Moore状态机即可实现输入时钟的5分频。占空比为3/5。
verilog代码如下:
module fsm_div5(
input clk,
output reg clk_div5,
input rst_n
);
reg [2:0] state;
reg [2:0] next_state;
parameter s1 = 3'b000,
s2 = 3'b001,
s3 = 3'b010,
s4 = 3'b011,
s5 = 3'b100;
always @(posedge clk) begin
if(!rst_n) begin
state <= s1;
end
else begin
state <= next_state;
end
end
always @(*) begin
case(state)
s1: next_state = s2;
s2: next_state = s3;
s3: next_state = s4;
s4: next_state = s5;
s5: next_state = s1;
default: next_state = s1;
endcase
end
always @(*) begin
if(!rst_n)
clk_div5 = 0;
else begin
case(state)
s1: clk_div5 = 0;
s2: clk_div5 = 0;
s3: clk_div5 = 1;
s4: clk_div5 = 1;
s5: clk_div5 = 1;
default: clk_div5 = 0;
endcase
end
end
endmodule
仿真代码如下:
module tb();
reg clk ;
reg rst_n ;
wire clk_div5;
parameter CLOCK_CYCLE = 20;
fsm_div5 DUT(
.clk (clk ),
.rst_n (rst_n),
.clk_div5 (clk_div5)
);
initial clk = 1'b0;
always #(CLOCK_CYCLE/2) clk = ~clk;
initial begin
rst_n = 1'b1;
#(CLOCK_CYCLE*2);
rst_n = 1'b0;
#(CLOCK_CYCLE*2);
rst_n = 1'b1;
#(CLOCK_CYCLE*50);
$finish();
end
initial begin
$fsdbDumpfile();
$fsdbDumpvars;
end
endmodule
波形如下: