有关奇分频的思考
(这篇文章的一些写法比较简洁)Verilog 分频器设计
占空比小于50%的两个clk信号
占空比大于50%的两个clk信号
对比
所以不要死板的记,以上面的2,3电平为例:如果高电平多,就需要交错半个clk周期进行与运算,正好去掉半个周期的,高低电平就相同了。
如果是低电平多,就是交错之后或运算,高低电平就相同。
Verilog任意分频器设计
把所有的分频模块并行同时进行,只是依据参数选择性的输出。
// parameter 参数化的方法将偶数分频和奇数分频都做成通用的任意分频模块,方便以后的调用
module divider_api
#(
parameter CLK_DIV = 12'd5, // 分频数
CNT_WIDTH = 12'd5 // 分频器位宽
)
(
input wire sys_clk , //系统时钟50Mhz
input wire sys_rst_n , //全局复位
output wire clk_out //对系统时钟分频后的信号
);
//偶分频信号
reg clk_even ;
reg [CNT_WIDTH-1 : 0] clk_even_cnt ;
//奇分频信号
wire clk_odd ;
reg clk_1 ;
reg clk_2 ;
reg [CNT_WIDTH-1 : 0] clk_1_cnt ;
reg [CNT_WIDTH-1 : 0] clk_2_cnt ;
//所有的分频模块时同时进行的,只是依据参数选择性的输出
assign clk_out = (CLK_DIV == 1) ? sys_clk : (CLK_DIV[0] ? clk_odd : clk_even); //只需判断最后一位是0还是1即可
assign clk_odd = clk_1 & clk_2;
//偶分频
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
begin
clk_even_cnt <= 0 ;
clk_even <= 1'b0 ;
end
else if(clk_even_cnt == CLK_DIV / 2 - 1) //计数到一半时翻转,计数器继续加
begin
clk_even_cnt <= clk_even_cnt + 1'b1;
clk_even <= ~clk_even;
end
else if(clk_even_cnt == CLK_DIV - 1 ) //计数满时翻转,计数器清零
begin
clk_even_cnt <= 0 ;
clk_even <= ~clk_even;
end
else //其他情况计数器加一,clkeven保持不变即可
begin
clk_even_cnt <= clk_even_cnt + 1'b1;
clk_even <= clk_even;
end
end
//奇分频——clk1:上升沿触发
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
begin
clk_1_cnt <= 0 ;
clk_1 <= 1'b0 ;
end
else if(clk_1_cnt == (CLK_DIV - 1) / 2) //计数到一半时翻转,计数器继续加
begin
clk_1_cnt <= clk_1_cnt + 1'b1 ;
clk_1 <= ~clk_1 ;
end
else if(clk_1_cnt == CLK_DIV - 1) //计数满时翻转,计数器清零
begin
clk_1_cnt <= 0 ;
clk_1 <= ~clk_1 ;
end
else
begin
clk_1_cnt <= clk_1_cnt + 1'b1 ;
clk_1 <= clk_1 ;
end
end
//奇分频——clk2:下降沿触发
always @(negedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
begin
clk_2_cnt <= 0 ;
clk_2 <= 1'b0 ;
end
else if(clk_2_cnt == (CLK_DIV - 1) / 2) //计数到一半时翻转,计数器继续加
begin
clk_2_cnt <= clk_2_cnt + 1'b1 ;
clk_2 <= ~clk_2 ;
end
else if(clk_2_cnt == CLK_DIV - 1) //计数满时翻转,计数器清零
begin
clk_2_cnt <= 0 ;
clk_2 <= ~clk_2 ;
end
else
begin
clk_2_cnt <= clk_2_cnt + 1'b1 ;
clk_2 <= clk_2 ;
end
end
endmodule
Testbench
`timescale 1ns/1ns
module divider_api_tb();
//wire define
wire clk_out;
//reg define
reg sys_clk;
reg sys_rst_n;
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50Mhz
always #10 sys_clk = ~sys_clk;
divider_api
#(
.CLK_DIV (12'd10),
.CNT_WIDTH (12'd5)
)
divider_api_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.clk_out (clk_out ) //output clk_out
);
endmodule
10分频
25分频