【马春杰杰】使用FPGA实现任意分频、二分频

来源:互联网 发布:网络贷款影响征信吗 编辑:程序博客网 时间:2024/04/30 02:51

二分频

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

实例如下:

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;    endendmodule

!!!在这里出现了一个问题,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=6)的RTL原理图:

偶分频(N=6)的RTL原理图

偶分频(N=6)的行为仿真结果:

偶分频(N=6)的行为仿真结果:

奇分频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;    endendalways@(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;    endendassign 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
原创粉丝点击