马春杰杰 Exit Reader Mode

[mcj]使用FPGA实现任意分频、二分频

分频

二分频应该是最简单的,就是每当检测到输入时钟的高电平时就将输出翻转一下就行了。

实例如下:

module div2(clk,clkout,reset);
    input clk;
    input reset;
    output clkout;
 
    reg clkout;
 
    always @(posedge clk or posedge reset)
    clkout =~ clkout;
 
endmodule

激励文件如下:

module div2_1;
    reg clk;
    reg reset;
 
    div2 d2 (clk,clkout,reset);
    always @ #20 clk=~clk;
 
    initial
    begin
        clk = 1'b0;
        reset = 1'b1;
        #24 reset = 1'b0;
    end
 
endmodule

!!!在这里出现了一个问题,always @ (posedge clk or negedge reset) 如果这样写的话,就会报错Assignment under multiple single edges is not supported for synthesis 只有把negedge换成posege才行,目前还不知道为什么会这样。

三分频

三分频的思想就是通过一个计数器,当累积到一定的数量的时候,就让输出信号进行翻转。这里的3分频占空比不是50%,而是75%。

实例如下

module div_3 (q,clk,reset);
    output q;
    input reset;
    input clk;
    reg q;
    reg [1:0] count;   //设了一个2位的计数器可以从00计数到11;
 
    always @ (posedge clk or posedge reset)   //同步复位,上升沿有效
    if (reset)     //复位
        begin
          q<=1'b0;
          count<=2'b00;
        end
    else if(count==2'b00)   //第一个CLK上升沿来的时候q翻转一次计数器加一;
        begin
            q<=~q;
            count<=count+1'b1;
        end
        else if(count==2'b10)  //第3个CLK上升沿来的时候输出q翻转一次计数器归零;
        begin
            q=~q;
            count<=2'b00;
        end
            else         //第二个CLK上升沿来的时候q不动作,计数器加一。   
            begin
                count<=count+1'b1;
            endendmodule

下面这个是我自己写的三分频:

module div3(clk,clkout,reset);
input clk;
input reset;
output clkout;
reg clkout;
reg [1:0] count;//第一个错误,count作为一个寄存器,要标明大小[n:m]
 
always @(posedge clk or posedge reset)
if (reset) 
    begin
        clkout <= 1'b0;
        count <= 2'b00;
    endelse if (count == 2'b00)
    begin
        clkout <= ~clkout;//第二个错误,clkout要用非阻塞语句,即<=而不是=
        count <= count+1;
    end 
else if (count == 2'b01) 
        count <= count+1;
else if (count == 2'b10)
    begin
        clkout <= ~clkout;
        count <= 2'b00;
    endendmodule

激励文件如下:

module top1;
    reg clk;
    reg reset;
    div_3 d3 (q,clk,reset);
    always #20 clk=~clk;
    initial     //initial中的语句只执行一次
    begin
        clk=1'b0;
        reset=1'b1;
        #24 reset =1'b0;
    endendmodule

任意分频

偶分频N

仿照之前3分频,当计数器记到2的时候,进行翻转。为什么这样呢?因为0代表第一个上升沿,1代表第二个上升沿,2代表第三个上升沿,所以我们想3分频,就需要在第三个上升沿的时候进行翻转,即N分频,就需要在第N个上升沿的时候进行翻转。

实例如下:

module divn(clk_out,clk_in,rst);
output clk_out;
input clk_in;
input rst;
reg [3:0] cnt;//这里改成[1:0]也可以,为什么呢,因为只需要记到N/2-1就可以了,这里N=6,所以最大也就是2,所以够用。reg clk_out;
parameter N=6;
always @ (posedge clk_in or posedge rst)
beginif(rst)
       begin
            cnt <= 0;
            clk_out <= 0;
       endelse begin
        if(cnt==N/2-1)
              begin 
                  clk_out <= !clk_out; 
                  cnt<=0; 
              end
        else
            cnt <= cnt + 1;
     endendendmodule

激励文件如下:

module divnn;
    // Inputs
    reg clk_in;
    reg rst;
    // Outputs
    wire clk_out;//这里改成reg就不行了,clkout的值就变成了X,不知道为什么
    // Instantiate the Unit Under Test (UUT)
    divn uut (
        .clk_out(clk_out), 
        .clk_in(clk_in), 
        .rst(rst)
    );
    always #20 clk_in=~clk_in;
    initial begin
        // Initialize Inputs
        clk_in = 1'b0;
        rst = 1'b1;
        #20 rst = 1'b0; 
    end      
endmodule

奇分频N

下面是实例程序,还没有看

关于奇分频的原理,讲解上是这么说的:

实现奇数(N)分频,分别用上升沿计数到(N-1)/2,再计数到N-1;用下降沿计数到(N-1)/2,再计数到N-1,得到两个波形,然后把它们相或即可得到N分频。

module fp_odd(clk_out,clk_p,clk_n,clk_in,rst);
output clk_out;
output clk_p,clk_n;
input clk_in,rst;
reg [2:0] cnt_p,cnt_n;
reg clk_p,clk_n;
parameter N=5;
always @ (posedge clk_in or negedge rst)
begin
       if(!rst)     cnt_p <= 0;
       else  if(cnt_p==N-1)    cnt_p <=0;
                else cnt_p <= cnt_p + 1;
endalways @ (posedge clk_in or negedge rst)
begin
    if(!rst) clk_p <= 0;
    else if(cnt_p==(N-1)/2)
               clk_p <= !clk_p;
       else if(cnt_p==N-1)
               clk_p <= !clk_p;
endalways @ (negedge clk_in or negedge rst)
begin
       if(!rst)     cnt_n <= 0;
       else  if(cnt_n==N-1)    cnt_n <=0;
                else cnt_n <= cnt_n + 1;
endalways @ (negedge clk_in or negedge rst)
begin
    if(!rst) clk_n <= 0;
    else if(cnt_n==(N-1)/2)
               clk_n <= !clk_n;
       else if(cnt_n==N-1)
               clk_n <= !clk_n;
endassign clk_out = clk_p | clk_n;
endmodule

任意的

最后一个是非常经典的,可以任意分频,只需要更改K的值即可。

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;
    endend
 
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
 
endassign clkk = (k%2)?clk1&clk2:clk1;
endmodule

下面是激励文件(只需要更改k的值即可,不过要注意寄存器的大小,不要超了):

module reny;
    // Inputs
    reg rst_n;
    reg clk;
    reg [3:0] k;
 
    // Outputs
    wire clkk;
 
    // Instantiate the Unit Under Test (UUT)
    m1k uut (
        .rst_n(rst_n), 
        .clk(clk), 
        .k(k), 
        .clkk(clkk)
    );
    always #20 clk=~clk;
    initial begin
        // Initialize Inputs
        rst_n = 0;
        clk = 0;
        k = 5;
        #24 rst_n=1;
    end      
endmodule
本文最后更新于2017年5月21日,已超过 1 年没有更新,如果文章内容或图片资源失效,请留言反馈,我们会及时处理,谢谢!