在fpga 设计中, 我们有时需要对输入的时钟进行分频。 例如:1/2,1/3,1/4,1/5 等等。在偶数分频时,分频逻辑比较容易实现,在奇数分频时,fpga 设计相对麻烦一些。
偶数分频逻辑设计:
even_div.v
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
module even_div # ( parameter [31:0] N = 2 ) ( input clk, output clk_out, input reset ); reg [31:0] cnt; always @(posedge clk or posedge reset) begin if(reset) cnt <= 0; else if(cnt == N - 1) cnt <= 0; else cnt <= cnt + 1; end reg clk_reg; always @(posedge clk or posedge reset) begin if(reset) clk_reg <= 0; else if(cnt == N/2 - 1) clk_reg <= ~clk_reg; else if(cnt == N - 1) clk_reg <= ~clk_reg; end assign clk_out = clk_reg; endmodule |
偶数分频相对比较简单, 程序中使用cnt 作为计数器, 当计数器计数到分频值的一半时(N/2), clk 反转; 当计数器计数到分频值(N)时, clk 再次反转。
odd_div.v
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
module odd_div # ( parameter [31:0] N = 3 ) ( input clk, output clk_out, input reset ); reg [31:0] cnt_p , cnt_n; reg clk_p , clk_n; localparam BAUD_HALF = (N-1)/2 - 1; localparam BAUD_TICK = N - 1; always @(posedge clk or posedge reset) begin if(reset) cnt_p <= 4'd0; else if(cnt_p == BAUD_TICK) cnt_p <= 0; else cnt_p <= cnt_p + 1'b1; end always @(negedge clk or posedge reset) begin if(reset) cnt_n <= 4'd0; else if(cnt_n == BAUD_TICK) cnt_n <= 0; else cnt_n <= cnt_n + 1'b1; end //clk_p always @(posedge clk or posedge reset) begin if(reset) clk_p <= 1; else if(cnt_p == BAUD_HALF) clk_p <= ~clk_p; else if(cnt_p == BAUD_TICK) clk_p <= ~clk_p; end //clk_n always @(negedge clk or posedge reset) begin if(reset) clk_n <= 1; else if(cnt_n == BAUD_HALF) clk_n <= ~clk_n; else if(cnt_n == BAUD_TICK) clk_n <= ~clk_n; end assign clk_out = clk_n | clk_p; endmodule |
奇数分频相对比较麻烦, 步骤如下:
1)需要两个计数器:clk 上升沿计数器; clk 下降沿计数器。这两个计数器实现N计数。
2)分别在clk 的上升沿和下降沿 实现 clk_p, clk_n。当cnt_x == N/2 – 0.5 时,clk_x 反转; 当cnt_x == N 时,clk_x 再次反转; 这样生成的时钟clk_x 是一个占空比不等的时钟(高电平 – 低电平 = 1)即要么高电平多0.5, 或者低电平多0.5 个时钟周期。
3)clk_out = clk_p | clk_n; 平衡占空比不等的现象,通过使用 或操作 ,实现%50 、%50 占空比的时钟。
仿真程序:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
`timescale 1ns / 1ps module tb ( ); parameter PERIOD = 20 ; //50Mhz reg clk; reg reset = 1; initial begin clk = 0; #(PERIOD/2); forever #(PERIOD/2) clk = ~clk; end initial begin reset = 1; @(posedge clk); reset = 0; #800000; $stop; end wire clk_out1; odd_div # ( .N (7) ) odd_div_inst ( .clk (clk), .clk_out (clk_out1), .reset (reset) ); wire clk_out2; even_div # ( .N (4) ) even_div_inst ( .clk (clk), .clk_out (clk_out2), .reset (reset) ); endmodule |
仿真波形:

从仿真波形上可以看出,通过或操作实现 %50 , %50 的占空比时钟,从而实现计数分频。 偶数分频相对简单一些,只要通过计数分频即可。