verilog时钟分频

数字电路设计许多模块都是由计数器与分频器组成的,例如 PWM 脉宽调制、频率计等。分频逻辑也往往通过计数逻辑完成。本文主要对偶数分频、奇数分频、半整数分频进行简单的总结。

偶数分频

采用触发器反向输出端连接到输入端的方式,可构成简单的 2 分频电路。

以此为基础进行级联,可构成 4 分频,8 分频电路。

电路实现如下图所示,用 Verilog 描述时只需使用简单的取反逻辑即可。

如果偶数分频系数过大,就需要对分频系数 N 循环计数,进行分频。在计数周期达到分频系数中间数值 N/2 时进行时钟翻转,可保证分频后时钟的占空比为 50%。因为是偶数分频,也可以对分频系数中间数值 N/2 进行循环计数。

偶数分频的 Verilog 描述举例如下。

1
module even_div #(parameter N=10) (
2
        input clk,
3
        input rstn,
4
        output clk_div2,
5
        output clk_div4,
6
        output clk_div10
7
    );
8
9
    // 2 分频
10
    reg clk_div2_r;
11
    always @(posedge clk or negedge rstn) begin
12
        if(!rstn) begin
13
            clk_div2_r <= 'b0;
14
        end
15
        else begin
16
            clk_div2_r <= ~clk_div2_r;
17
        end
18
    end
19
    assign clk_div2 = clk_div2_r;
20
21
    // 4 分频
22
    reg clk_div4_r;
23
    always @(posedge clk_div2 or negedge rstn) begin
24
        if (!rstn) begin
25
            clk_div4_r <= 'b0;
26
        end
27
        else begin
28
            clk_div4_r <= ~clk_div4_r;
29
        end
30
    end
31
    assign clk_div4 = clk_div4_r;
32
33
    // N/2 计数
34
    reg [3:0] cnt;
35
    always @(posedge clk or negedge rstn) begin
36
        if(!rstn) begin
37
            cnt <= 'b0;
38
        end
39
        else if(cnt == (N/2-1)) begin
40
            cnt <= 'b0;
41
        end
42
        else begin
43
            cnt <= cnt + 1;
44
        end
45
    end
46
    // 输出时钟
47
    reg clk_div10_r;
48
    always @(posedge clk or negedge rstn) begin
49
        if (!rstn) begin
50
            clk_div10_r <= 'b0;
51
        end
52
        else if(cnt == (N/2 - 1)) begin
53
            clk_div10_r <= ~clk_div10_r;
54
        end
55
    end
56
    assign clk_div10 = clk_div10_r;
57
endmodule

仿真结果如下:

奇数分频

奇数分频如果不要求占空比为 50%,可按照偶数分频的方法进行分频。即计数器对分频系数 N 进行循环计算,然后根据计数值选择一定的占空比输出分频时钟。

如果奇数分频输出时钟的高低电平只差一个 cycle ,则可以利用源时钟双边沿特性并采用”与操作”或”或操作”的方式将分频时钟占空比调整到 50%。

或操作调整占空比

实现思路:

假设实现N分频(N为奇数,占空比为50%),在输入时钟上升沿下计数到 N-1,同时在 0 和 (N-1)/2 处时钟信号1翻转;在输入时钟下降沿下计数到 N-1,同时在 0 和 (N-1)/2 处时钟信号2翻转;最后信号1和信号2进行相或。

三分频和五分频电路:

verilog实现:

下面是一个9分频的例子:

1
module odd_div_or #(parameter N = 9) (
2
	input rstn, clk,
3
    output clk_div
4
);
5
    // 计数器
6
    reg [3:0] cnt;
7
    always @(posedge clk or negedge rstn) begin
8
        if(!rstn) begin
9
           cnt <= 'b0; 
10
        end
11
        else if(cnt == N-1) begin
12
            cnt <= 'b0;
13
        end
14
        else begin
15
           cnt <= cnt + 1'b1; 
16
        end
17
    end
18
    
19
    // 在上升沿,计数器==(N-1)/2, N-1 翻转
20
    reg clk_p_r;
21
    always @(posedge clk or negedge rstn) begin
22
        if(!rstn) begin
23
           clk_p_r <= 1'b0; 
24
        end
25
        else if((cnt_p == (N-1)/2) || (cnt_p == (N-1))) begin
26
            clk_p_r <= ~clk_p_r;
27
        end
28
    end
29
30
    // 在下降沿,计数器==(N-1)/2, N-1 翻转
31
    reg clk_n_r;
32
    always @(negedge clk or negedge rstn) begin
33
        if(!rstn) begin
34
           clk_n_r <= 1'b0; 
35
        end
36
        else if((cnt == (N-1)/2) || (cnt == (N-1))) begin
37
        	clk_n_r <= ~clk_n_r;
38
        end
39
    end
40
    
41
    assign clk_div = clk_p_r | clk_n_r;
42
                    
43
endmodule

小数分频

实现思路:
假设实现N.5分频(N为整数),在输入时钟上升沿下计数到 2N,同时在 0 和 N+1 处时钟信号1翻转;在输入时钟下降沿下计数到 2N,同时在 0 和 N 处时钟信号2翻转;最后信号1和信号2进行相与。

例1.5分频:

1
module div_3p2 #(parameter N=1) (
2
	input clk, rstn
3
    output clk_div
4
);
5
    reg [2:0] cnt_p;
6
    reg [2:0] cnt_n;
7
    reg clk_p_r, clk_n_r;
8
    
9
    //上升沿计数
10
    always @(posedge clk or negedge rstn) begin
11
        if(!rstn) begin
12
           cnt_p <= 'b0; 
13
        end
14
        else if(cnt_p == 2*N) begin
15
           cnt_p <= 'b0; 
16
        end
17
        else begin
18
           cnt_p <= cnt_p + 1'b1; 
19
        end
20
    end
21
    //上升沿分频
22
    always @(posedge clk or negedge rstn) begin
23
        if(!rstn) begin
24
           clk_p_r <= 1'b0; 
25
        end
26
        else if(cnt_p == N+1 || cnt_p == 0) begin
27
           clk_p_r <= ~clk_p_r; 
28
        end
29
    end
30
    
31
    //下降沿计数
32
    always @(negedge clk or negedge rstn) begin
33
        if(!rstn) begin
34
           cnt_n <= 'b0; 
35
        end
36
        else if(cnt_n == 2*N) begin
37
           cnt_n <= 'b0; 
38
        end
39
        else begin
40
           cnt_n <= cnt_n + 1'b1; 
41
        end
42
    end
43
    //下降沿分频
44
    always @(negedge clk or negedge rstn) begin
45
        if(!rstn) begin
46
           clk_n_r <= 1'b1; 
47
        end
48
        else if(cnt_n == N || cnt_n == 0) begin
49
           clk_n_r <= ~clk_n_r; 
50
        end
51
    end
52
    assign clk_div = clk_n_r & clk_p_r;
53
endmodule

分数分频

小数分频电路可以转化为特定分频比电路设计问题。如19/9分频,意味着在输入时钟clk_in的19个周期内,输出需产生9个脉冲。因为19/9 = 2.11…, 因此可以用2分频和3分频配合实现,设待分频时钟的19个周期内共有x个二分频时钟周期,y个三分频时钟周期,则有:

x+y=9

2x+3y=19

解得x=8,y=1。即只要在待分频时钟的19个周期内控制输出8个二分频时钟周期和1个三分频时钟周期即可。具体代码思路:

1)首先一个总的计数器,在0-18循环;

2)其次设计两个分别生成2分频和3分频的计数器,根据总计数器的数值范围分别在0-1和0-2循环;

3)最后是波形生成逻辑,根据总计数器和2、3分频计数器的数值控制输出脉冲翻转生成期望分频比的时钟。

19/9的分频电路代码如下,其余分频比也可参考:

1
// M/N小数分频,M为分子,N为分母
2
module Dec_Freq_Div_M_N(
3
 input clk,
4
 input rstn,
5
 output clk_out
6
);
7
8
reg [5:0] cnt;
9
reg [3:0] cnt_a;
10
reg [3:0] cnt_b;
11
reg clk_out_reg;
12
assign clk_out = clk_out_reg;
13
14
// div_a和div_b分别为根据前述公式计算出来的基准分频系数
15
// change为2、3分频时钟的切换点
16
parameter M = 6'd19;
17
parameter change = 6'd16;
18
parameter div_a = 5'd2;
19
parameter div_b = 5'd3;
20
21
//总计数器
22
always @(posedge clk or negedge rstn) begin
23
 if(!rstn)
24
  cnt <= 6'b0;
25
 else begin
26
  if(cnt == M - 1'b1)
27
   cnt <= 6'b0;
28
  else
29
   cnt <= cnt + 1'b1;
30
 end 
31
end 
32
33
//产生2、3分频的计数器
34
always @(posedge clk or negedge rstn) begin 
35
 if(!rstn) begin
36
  cnt_a <= 4'b0;
37
  cnt_b <= 4'b0;
38
 end 
39
 else if(cnt<=change-1'b1) begin
40
  cnt_b <= 4'd0;
41
  if(cnt_a == div_a - 1'b1)
42
   cnt_a <= 4'd0;
43
  else
44
   cnt_a <= cnt_a + 1'b1;
45
 end 
46
 else if(cnt>change-1'b1) begin
47
  cnt_a <= 4'd0;
48
  if(cnt_b == div_b - 1'b1)
49
   cnt_b <= 4'd0;
50
  else
51
   cnt_b <= cnt_b + 1'b1;
52
 end
53
54
//输出时钟产生逻辑
55
always @(posedge clk or negedge rstn) begin
56
 if(!rstn)
57
  clk_out_reg <= 1'b0;
58
 else if(cnt<change) begin
59
  if(cnt_a == 4'd0 || cnt_a == div_a/2)
60
   clk_out_reg <= ~clk_out_reg;
61
  else
62
   clk_out_reg <= clk_out_reg;
63
 end 
64
 else if(cnt>=change) begin
65
  if(cnt_b == 4'd0 || cnt_b == (div_b - 1'b1)/2)
66
   clk_out_reg <= ~clk_out_reg;
67
  else
68
   clk_out_reg <= clk_out_reg;
69
 end 
70
end 
71
72
endmodule