Verilog设计思路05——时钟分频_时钟二分频代码
在 Verilog 中,时钟分频是常见的操作,用于生成不同频率的时钟信号以满足不同模块的需求。下面为你详细讲解几种常见的时钟分频方式,并给出对应的代码示例。
一、偶数分频
1、原理
- 偶数分频是最容易实现的分频方式,通过一个计数器对时钟信号进行计数,当计数器达到分频系数的一半时,将输出时钟信号取反,然后重新开始计数。
2、代码示例
module even_divider #(
parameter DIVISOR = 4 // 分频系数,这里设置为 4 分频 ) (
input wire clk, // 输入时钟信号
input wire rst_n, // 异步复位信号,低电平有效
output reg clk_out // 输出分频后的时钟信号 );reg [31:0] counter; // 计数器always @(posedge clk or negedge rst_n) begin if (!rst_n) begin counter <= 0; clk_out <= 0; end else if (counter == (DIVISOR / 2 - 1)) begin counter <= 0; clk_out <= ~clk_out;
…
3、代码解释
-
DIVISOR 是一个参数,用于指定分频系数,这里默认设置为 4 分频。
-
counter 是一个 32 位的计数器,用于记录时钟周期数。
-
在时钟上升沿或复位信号下降沿触发的 always 块中:
-
当复位信号有效时,计数器和输出时钟信号都被清零。
-
当计数器达到 DIVISOR / 2 - 1 时,计数器清零,输出时钟信号取反。否则,计数器加 1。
二、奇数分频
1、原理
- 奇数分频相对复杂一些,通常需要分别对时钟信号的上升沿和下降沿进行计数,然后将两个计数结果进行逻辑组合得到最终的分频时钟信号。
2、代码示例
代码片段
module odd_divider #(
parameter DIVISOR = 3 // 分频系数,这里设置为 3 分频 ) (
input wire clk, // 输入时钟信号
input wire rst_n, // 异步复位信号,低电平有效
output reg clk_out // 输出分频后的时钟信号 );reg [31:0] counter_pos; // 上升沿计数器reg [31:0] counter_neg; // 下降沿计数器reg clk_pos; // 上升沿分频时钟reg clk_neg; // 下降沿分频时钟// 上升沿计数always @(posedge clk or negedge rst_n) begin if (!rst_n) begin counter_pos <= 0; clk_pos <= 0; end else if (counter_pos == (DIVISOR - 1)) begin counter_pos <= 0; clk_pos <= ~clk_pos; end else if (counter_pos == ((DIVISOR - 1) / 2)) begin clk_pos <= ~clk_pos; counter_pos <= counter_pos + 1; end else begin counter_pos <= counter_pos + 1; endend
3、代码解释
-
DIVISOR 是一个参数,用于指定分频系数,这里默认设置为 3 分频。
-
counter_pos 和 counter_neg 分别是上升沿和下降沿的计数器。
-
clk_pos 和 clk_neg 分别是上升沿和下降沿的分频时钟信号。
-
在上升沿和下降沿触发的 always 块中,分别对计数器进行计数,并在适当的时候对分频时钟信号取反。
-
最后,通过逻辑或运算将上升沿和下降沿的分频时钟信号组合成最终的分频时钟信号。
三、半整数分频(如2.5分频)
1、原理:交替使用2分频和3分频,通过组合正负沿信号生成。
2、示例(2.5分频):
代码片段
module half_div (
input clk, rst_n,
output clk_out );
reg clk1, clk2;
reg [1:0] cnt;always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 0; clk1 <= 0; end else begin cnt <= cnt + 1; if (cnt == 1) clk1 <= ~clk1; // 2分频部分 if (cnt == 2) begin clk1 <= ~clk1; // 3分频部分 cnt <= 0; end end end
…
3、关键点:适用于非整数分频场景,如2.5、3.5分频16。
四、小数分频(如5/2分频)
1、原理:通过累加器控制分频系数切换,实现近似小数分频。
2、示例(5/2=2.5分频):
module frac_div #(parameter NUM=5, DEN=2) (
input clk, rst_n,
output reg clk_out );
reg [7:0] acc;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
acc <= 0;
clk_out <= 0;
end
else begin
acc <= acc + NUM;
if (acc >= DEN) begin
acc <= acc - DEN;
clk_out <= ~clk_out; // 分频切换
end
end
…
五、任意分频
1、原理
任意分频可以通过对偶数分频和奇数分频的方法进行扩展来实现。可以根据分频系数的奇偶性选择不同的分频方法。
2、代码示例
代码片段
module arbitrary_divider #(
parameter DIVISOR = 5 // 分频系数,这里设置为 5 分频 ) (
input wire clk, // 输入时钟信号
input wire rst_n, // 异步复位信号,低电平有效
output reg clk_out // 输出分频后的时钟信号 );reg [31:0] counter; // 计数器reg clk_pos; // 上升沿分频时钟reg clk_neg; // 下降沿分频时钟// 判断分频系数的奇偶性localparam IS_ODD = (DIVISOR % 2 == 1);// 上升沿计数always @(posedge clk or negedge rst_n) begin if (!rst_n) begin counter <= 0; clk_pos <= 0; end else if (counter == (DIVISOR - 1)) begin counter <= 0; clk_pos <= ~clk_pos; end else if (IS_ODD && counter == ((DIVISOR - 1) / 2)) begin clk_pos <= ~clk_pos; counter <= counter + 1; end else if (!IS_ODD && counter == (DIVISOR / 2 - 1)) begin counter <= 0; clk_pos <= ~clk_pos; end else begin counter <= counter + 1; endend
…
3、代码解释
DIVISOR 是一个参数,用于指定分频系数,这里默认设置为 5 分频。
IS_ODD 是一个局部参数,用于判断分频系数的奇偶性。
在上升沿触发的 always 块中,根据分频系数的奇偶性进行不同的计数和时钟信号取反操作。
当分频系数为奇数时,使用 generate 块生成下降沿计数的 always 块。
最后,根据分频系数的奇偶性将上升沿和下降沿的分频时钟信号组合成最终的分频时钟信号。
这些代码示例可以帮助你理解 Verilog 中不同类型的时钟分频实现方法。你可以根据需要调整分频系数来实现不同的分频效果。