【常用电路】奇数/偶数分频电路

一、偶数分频电路

  偶数倍分频是最简单的一种分频模式,完全可通过计数器计数实现。

 1 //////////////////////////////////////////////////////////////////////////////////
 2 // 偶数分频电路
 3 // 这个分频模块适用于待分频时钟和目标时钟的频率呈整倍数关系
 4 // 通过改变cnt_values确定是N分频,cnt_values应该等于N/2-1,以16分频为例,cnt_values=7;
 5 
 6 module clk_div_even(
 7     clk_in,
 8     reset,
 9     clk_out
10     );
11     
12 input       clk_in;
13 input       reset;
14 output      clk_out;
15 
16 reg             clk_out;
17 reg    [15:0]   cnt;
18 
19 parameter       cnt_values = 'd7;
20 
21 always @ ( posedge clk_in ) begin
22     if ( reset ) begin
23         cnt <= 16'b0;
24         clk_out <= 1'b0;
25         end
26     else if ( cnt == cnt_values ) begin
27         cnt <= 16'b0;
28         clk_out <= ~clk_out;
29         end
30     else begin
31         cnt <= cnt + 1'b1;
32         clk_out <= clk_out;
33         end
34     end
35         
36 endmodule

 

二、奇数分频电路

  相较于偶数倍分频,奇数倍分频要复杂一些。奇数倍分频有多种方法,下面介绍错位“异或”法,主要在时钟的上升沿和下降沿分别产生占空比非50%的时钟,再进行或运算。

 1 //////////////////////////////////////////////////////////////////////////////////
 2 // 奇数分频电路
 3 // 这个分频模块适用于待分频时钟和目标时钟的频率呈整倍奇数关系
 4 // 通过相或运算实现50%占空比的奇数N分频,N=cnt_values;
 5 
 6 module clk_div_odd(
 7     clk_in,
 8     reset,
 9     clk_out
10     );
11     
12 input       clk_in;
13 input       reset;
14 output      clk_out;
15 
16 reg    [15:0]   cnt_p, cnt_n;
17 reg    [15:0]   cnt_values = 'd3;
18 reg             clk_p, clk_n;
19 
20 always @ ( posedge clk_in ) begin
21     if ( reset ) begin
22         cnt_p <= 16'b0;
23         clk_p <= 1'b0;
24         end
25     else if ( cnt_p == 16'b0 ) begin
26         cnt_p <= cnt_p + 16'b1;
27         //cnt_p <= 16'b0;
28         clk_p <= ~clk_p;
29         end
30         
31     else if ( cnt_p == (cnt_values - 16'b1)/2 ) begin
32         cnt_p <= cnt_p + 16'b1;
33         //cnt_p <= 16'b0;
34         clk_p <= ~clk_p;
35         end
36     else if ( cnt_p == (cnt_values - 16'b1))begin
37         cnt_p <= 16'b0;
38         //cnt_p <= cnt_p + 16'b1;
39         clk_p <= clk_p;
40         end
41     else begin
42         cnt_p <= cnt_p + 16'b1;
43         clk_p <= clk_p;
44         end
45     end
46         
47 
48 always @ ( negedge clk_in ) begin
49     if ( reset ) begin
50         cnt_n <= 16'b0;
51         clk_n <= 1'b0;
52         end
53     else if ( cnt_n == 16'b0 ) begin
54         cnt_n <= cnt_n + 16'b1;
55         //cnt_p <= 16'b0;
56         clk_n <= ~clk_n;
57         end
58     else if ( cnt_n == (cnt_values - 16'b1)/2 ) begin
59         cnt_n <= cnt_n + 16'b1;
60         //cnt_p <= 16'b0;
61         clk_n <= ~clk_n;
62         end
63     else if ( cnt_n == (cnt_values - 16'b1))begin
64         cnt_n <= 16'b0;
65         //cnt_p <= cnt_p + 16'b1;
66         clk_n <= clk_n;
67         end
68     else begin
69         cnt_n <= cnt_n + 16'b1;
70         clk_n <= clk_n;
71         end
72     end
73 
74 
75 assign clk_out = clk_p | clk_n;         //两个占空比非50%的时钟相或之后,得到占空比50%的时钟
76     
77 endmodule

三、半整数分频

  利用时钟的双边沿逻辑,可以对时钟进行半整数的分频。但是无论怎么调整,半整数分频的占空比不可能是 50%。半整数分频的方法有很多,这里只介绍一种和奇数分频调整占空比类似的方法。

对任意N:复位之后,在一个上升沿进行上升沿计数,计数到2N清零,并且在0和N+1+N/2的时候进行翻转,得到clk_p;
复位之后,在一个下降沿进行下降沿计数,计数到6清零,并且在N/2和N的时候进行翻转,得到clk_n。

 1 module clk_div(
 2     input                clk,
 3     input                rst_n,
 4     output                clk_out
 5     );
 6 
 7     `define     DIV_CLK_N     63        // N.5分频
 8 
 9     reg                    clk_2in;                // 2N倍频时钟
10     reg                    clk_2in_2;                // 下降沿2N倍频时钟
11     reg       [7:0]        cnt_2N;                    // 2N倍频时钟计数
12     reg       [7:0]        cnt_2N_2;                // 下降沿2N倍频时钟计数
13 
14     assign        clk_out =     clk_2in && clk_2in_2;
15     
16 // 上升沿生成2N分频时钟电路
17 always@(posedge clk or negedge rst_n) begin
18     if(!rst_n)                          cnt_2N <= 8'b0;
19     else if(cnt_2N == 2*`DIV_CLK_N)     cnt_2N <= 8'b0;
20     else cnt_2N <= cnt_2N + 1'b1;
21 end
22 
23 always@(posedge clk or negedge rst_n) begin
24     if(!rst_n)                      clk_2in <= 1'b0;
25     //else if((cnt_2N == `DIV_CLK_N+1) ||( cnt_2N ==0 )) begin                    // 这个是占空比为1:2N+1,未改进
26     else if((cnt_2N == `DIV_CLK_N+1+`DIV_CLK_N/2) ||( cnt_2N ==0 )) begin        // 这个是占空比尽量靠近0.5的方式
27         clk_2in <= ~clk_2in;
28     end
29     else clk_2in <= clk_2in;
30 end
31     
32 // 下降沿生成2N分频时钟电路
33 always@(negedge clk or negedge rst_n) begin
34     if(!rst_n)                          cnt_2N_2 <= 8'b0;
35     else if(cnt_2N_2 == 2*`DIV_CLK_N)   cnt_2N_2 <= 8'b0;
36     else cnt_2N_2 <= cnt_2N_2 + 1'b1;
37 end
38 
39 always@(negedge clk or negedge rst_n) begin
40     if(!rst_n)                      clk_2in_2 <= 1'b1;
41     //else if((cnt_2N_2 == `DIV_CLK_N) ||( cnt_2N_2 == 0 )) begin            // 这个是占空比为1:2N+1,未改进
42     else if((cnt_2N_2 == `DIV_CLK_N) ||( cnt_2N_2 == `DIV_CLK_N/2 )) begin    // 这个是占空比尽量靠近0.5的方式
43         clk_2in_2 <= ~clk_2in_2;
44     end
45     else clk_2in_2 <= clk_2in_2;
46 end  
47     
48 endmodule

 

三、仿真

附上tb文件

 1 module odd_sim;
 2 
 3 
 4 reg     clk_in;
 5 reg     reset;
 6 wire    clk_out;
 7 
 8 initial
 9 begin
10     clk_in = 1'b0;
11     reset = 1'b1;
12     
13     #1000
14     reset = 1'b0;
15     
16 end
17 
18 always #50 clk_in = ~clk_in;       //给时钟激励,即50ns翻转一次,10MHz
19 
20 clk_div_odd        odd_sim(
21     .clk_in         (clk_in),
22     .reset          (reset),
23     .clk_out        (clk_out)          
24 );
25 endmodule

 

posted @ 2021-10-30 00:51  AnchorX  阅读(771)  评论(0编辑  收藏  举报