一、计数器
计数器波形图:
verilog代码:
//2023/4/11 lzp 计数器实现
`timescale 1ns/1ns
module counter(
input wire sys_clk,
input wire sys_rst_n,//_n表示低电平
output reg[1:0] led_out //用always赋值,所以要用reg
);
parameter CNT_MAX = 25_000_000 - 1;
reg[24:0] cnt;
reg flag;
//异步复位,使用异步复位更好
//cnt计数
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) begin
cnt <= 1'b0;
end
else begin
if(cnt == CNT_MAX) begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) begin
led_out <= 2'b01;
flag <= 1'b0;
end
else begin
if(cnt == CNT_MAX) begin
flag <= flag + 1;
case(flag)
0: led_out <= 2'b01;
1: led_out <= 2'b10;
default: led_out <= 2'b00;
endcase
end
end
endmodule
/* module counter_tb();
reg sys_clk;
reg sys_rst_n;//_n表示低电平
wire[1:0] led_out; //用always赋值,所以要用reg\
counter counter(
sys_clk,
sys_rst_n,
led_out
);
initial begin
sys_clk = 0;
sys_rst_n <= 0;
#20
sys_rst_n <= 1;
end
always#10 sys_clk = ~sys_clk;
endmodule */
管脚绑定:
上板调试:
烧录后即可看到D6和D7led分别闪烁:
二、分频器
1. 偶分频
分配器基于计数器的实现。
六分频波形图:
verilog代码:
//2023/4/11 lzp 六分频
`timescale 1ns/1ns
module counter(
input wire sys_clk,
input wire sys_rst_n,
output reg six_clk
);
parameter CNT_MAX = 3 - 1;
reg[1:0] cnt;
//异步复位,使用异步复位更好
//cnt计数
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) begin
cnt <= 1'b0;
end
else begin
if(cnt == CNT_MAX) begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) begin
six_clk <= 1'b0;
end
else begin
if(cnt == CNT_MAX) begin
six_clk <= ~six_clk;
end
end
endmodule
module counter_tb();
reg sys_clk;
reg sys_rst_n;//_n表示低电平
wire six_clk;
counter counter(
sys_clk,
sys_rst_n,
six_clk
);
initial begin
sys_clk = 0;
sys_rst_n <= 0;
#20
sys_rst_n <= 1;
end
always#10 sys_clk = ~sys_clk;
endmodule
仿真波形图:
但这样设计出来的分频是有问题的,在高速系统中不能保证时钟到达每个寄存器的时间是相同的,所以需要进行改进:
改进版verilog:
//2023/4/11 lzp 六分频
`timescale 1ns/1ns
module counter(
input wire sys_clk,
input wire sys_rst_n,
output reg six_clk
);
parameter CNT_MAX = 6 - 1;
reg[2:0] cnt;
//异步复位,使用异步复位更好
//cnt计数
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) begin
cnt <= 1'b0;
end
else begin
if(cnt == CNT_MAX) begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) begin
six_clk <= 1'b0;
end
else begin
if(cnt == CNT_MAX) begin
six_clk <= 1;
end
else begin
six_clk <= 0;
end
end
endmodule
module counter_tb();
reg sys_clk;
reg sys_rst_n;//_n表示低电平
wire six_clk;
counter counter(
sys_clk,
sys_rst_n,
six_clk
);
initial begin
sys_clk = 0;
sys_rst_n <= 0;
#20
sys_rst_n <= 1;
end
always#10 sys_clk = ~sys_clk;
endmodule
波形图:
两者方法的对比如下,一个使用输出的时钟作为触发,一个还是使用系统时钟clk作为触发:
2. 奇分频
如果使用奇分频的话,实现要稍微比偶分频复杂一点(因为要保持50%的占空比),下面是五分频的占空比:
实现方法是将上升沿触发得到的clk_out和下降沿得到的clk_out进行或操作,即可得到最后的百分之50的占空比的输出信号。