笨笨笔记---分频器的设计

    技术2022-07-07  32

    <!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} p {mso-margin-top-alt:auto; margin-right:0cm; mso-margin-bottom-alt:auto; margin-left:0cm; mso-pagination:widow-orphan; font-size:12.0pt; font-family:宋体; mso-bidi-font-family:宋体;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} -->

    2011 1 10 17 24 58

    分频方法解析

    分频是最基本的操作之一,根据系数不同,有偶数分频,奇数分频,小数分频之分,根据使用的方法不同有:纯粹计数器法,单一计数器法,双重计数器法,奇数分频根据信号的生成方式,有与法,或法。

    一:纯粹计数法(利用最高数据位的自然溢出)

    如果是 25MHz 的时钟,那么这里利用数据的自然溢出,也就是取其最高位,而得到其输出频率为: 25000000/65536=381Hz ,周期为 1/381s ,则高电平时间为 1/(2*381)s ,其对应的计数值为: 32768

    module music(clk, speaker); input clk; output speaker; // Binary counter, 16-bits wide reg [15:0] counter; always @(posedge clk) counter <= counter+1; // Use the highest bit of the counter (MSB) to drive the speaker assign speaker = counter[15];// 只要 counter>=32767 ,那么 counter[15] 就等于 1 了,因为这里的计数是自然溢出的,所以低于 32767 和高于 32767 数据刚好各占用一半,所以占空比就是 50% 了。 endmodule

    其中 counter[0] 的频率是 12.5MHz counter[1] 的频率是 6.125MHz ,以此类推。它是按照 2 n+1 次方来分频的,且是方波。

     

    分频率为 440Hz ,这时就要除另外一个数了 440=25M/56818 ,代码如下:

    module music(clk, speaker); input clk; output speaker; reg [15:0] counter; always @(posedge clk) if (counter==56817) counter <= 0; else counter <= counter+1; assign speaker = counter[15];// 因为这里 56817 大于 32767 ,所以 counter[15] 还是会大于 1 endmodule

    但是这里有个问题,其占空比不是 50 ,而是 42% (56817 32768 /56817 ),为了得到占空比为 50% 的信号,最简单的方法是加一个中间信号,所以我们先除以 28409(56818/2) ,然后再除 2.

    module music(clk, speaker); input clk; output speaker; reg [14:0] counter; always @(posedge clk) if(counter==28408) counter <= 0; else counter <= counter+1; reg speaker;// 注意,这里不是利用最高位和自然溢出了,而是利用达到最高位翻转 always @(posedge clk) if(counter==28408) speaker <= ~speaker; // 信号翻转,也就是除以 2 endmodule

    参数化的表达方法

    module music(clk, speaker); input clk; output speaker; parameter clkdivider = 25000000/440/2; reg [14:0] counter; always @(posedge clk) if (counter==0) counter <= clkdivider-1; else counter <= counter-1; reg speaker; always @(posedge clk) if (counter==0) speaker <= ~speaker;// 信号翻转,也就是除以 2 endmodule

     

    二:偶数分频

           假设分频系数为 N( 偶数 ) ,则计数器的值计算从 0~N/2 ,然后信号翻转

    module N_bit_even_divider (

    output reg o_clk, input       i_clk, input       rst_n );

    parameter N = N_even; // 设置偶数倍分频

    parameter M = ?;      // M="N/2-1"

    // bit_of_N: N_even 的二进制位宽 reg [(bit_of_N - 1):0] cnt; // 计数器单元

    // 上升沿计数 : 0~(N-1) always @ (posedge i_clk, negedge rst_n) begin if (!rst_n)    cnt <= 0; else begin     if (cnt == N-1)       cnt <= 0;     else       cnt <= cnt + 1'b1;// 这里将计数和根据计数值来输出电平,分开来做,这符合低级建模的思想 end end

    // 生成上升沿时钟 // 0~(N/2-1) ↑ -> 1; (N/2)~(N-1) ↑ -> 0 always @ (posedge i_clk, negedge rst_n) begin if (!rst_n)     o_clk <= 0; else begin     if (cnt <= M)

          o_clk <= 1;// 在小于 N/2 时,输出 1 ,大于 N/2 时,输出 0     else       o_clk <= 0;// 这里信号是人为的规定其高低值,和下面的手动翻转功能是一样的,个人喜欢用下面的方式    end end

    endmodule

     

    module odd_division(clk,rst,count,clk_odd);     /*count 没必要放在端口中,这里只是为了仿真时观察 */

    input        clk,rst;

    output       clk_odd;

    output[3:0] count;

    reg          clk_odd;

    reg[3:0]     count;

    parameter    N = 6;                     /*6 分频 * /

        always @ (posedge clk)

          if(! rst)

            begin

              count <= 1'b0;

              clk_odd <= 1'b0;

            end

          else      

            if ( count < N/2-1)

              begin          

                count <= count + 1'b1;            

              end

            else

              begin        

                count <= 1'b0; / / 赋值和信号输出是两部分动作,所以最好将其分开

                clk_odd <= ~clk_odd;  // 信号手动翻转     

              end

    endmodule

     

           从上面可以看出,根据低级建模的思想:可以将偶数分频代码分为两种实现方式,计数和输出分离式,计数和输出不分离式,显然前者更加符合低级建模的思想。

     

    三:奇数分频

           根据最后输出频率的产生方式,可以分为两类:与式输出,或式输出。二者的输出占空比都为 50% 。另外,奇数分频使用了双边沿触发,这一点要注意。

    本人在此基础上实现了任意kk 为大于等于2 的自然数)倍分频,只要输入一个k 就相应的产生一个占空比为50% 的时钟,而频率为输入时钟的1/k. 主要思想参照上面介绍的,内部两个计数器,一个在输入时钟上升沿计数,另一个在下降沿计数,当计数到k>>1-1k-1 时分别翻转,这样可以产生两 个时钟:上升沿产生的k 分频时钟clk1 ,下降沿产生的k 分频时钟clk2 ,当k 为奇数时,将两个时钟clk1clk2 进行与运算,就可以得出占空比为 50% 的奇数倍分频时钟;而当k 为偶数时,取clk1 就刚好是分频好了的,占空比为50% 的时钟。

          下面是程序

    与式

    module m1k(rst_n,clk,k,clkk);

    input rst_n; input clk; input [3:0] k; reg clk1; reg clk2;

    output clkk; reg [3:0] k1; reg [3:0] k2;

    always@(negedge rst_n or posedge clk) begin   if(~rst_n)     begin     k1 <= 4'b0;     clk1 <= 1'b0;     end   else    begin     if(k1==(k-1))       clk1 <= ~clk1;     if(k1==((k>>1)-1'b1))        clk1 <= ~clk1;         if(k1==k-1)        k1 <= 4'b0000;     else        k1 <= k1+4'b0001;             end   end

    always@(negedge rst_n or negedge clk) begin   if(~rst_n)     begin     k2 <= 4'b0;     clk2 <= 1'b0;    end   else    begin     if(k2 == k-1)        k2 <= 4'b0000;     else        k2 <= k2+4'b0001;     if(k2==k-1)        clk2 <= ~clk2;     if(k2==((k>>1)-1'b1))        clk2 <= ~clk2;     end   end assign clkk = (k%2)?clk1&clk2:clk1; endmodule

     

    或式:

    module even_division(clk,rst,count1,count2,clk_even); /*count1 count2 没必要放在端口中,这里只是为了仿真时观察*/

    input        clk,rst;

    output[3:0] count1,count2;

    output       clk_even;

    reg[3:0]     count1,count2;

    reg          clkA,clkB;

    wire         clk_even,clk_re;

    parameter    N = 5;          /*5 分频*/

    assign clk_re   = ~clk;

    assign clk_even = clkA | clkB;

        always @(posedge clk)

          if(! rst)  

            begin

              count1 <= 1'b0;

              clkA <= 1'b0;          

            end

          else

            if(count1 < (N - 1))

             begin

             count1 <= count1 + 1'b1; // 注意这里应该是非阻塞赋值

                if(count1 == (N - 1)/2)

                  begin

                    clkA <= ~clkA; // 当计数到一半时,翻转信号

                  end                

              end          

            else // 计数到最大时,再次翻转信号

              begin

                clkA <= ~clkA;

                count1 <= 1'b0;

              end          

              

    always @ (posedge clk_re)

        if(! rst)

          begin

            count2 <= 1'b0;

            clkB <= 1'b0;

          end

        else

          if(count2 < (N - 1))

            begin

              count2 <= count2 + 1'b1;            

                if(count2 == (N - 1)/2)

                  begin

                    clkB <= ~clkB;

                  end                

            end          

          else

            begin

              clkB <= ~clkB;

              count2 <= 1'b0;

            end          

    endmodule

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    最新回复(0)