Verilog实现各类分频器

1. 偶数分频器

  • 偶数分频器的实现较为简单,用计数器即可实现
// 偶数分频器示例,20分频即N=10,占空比50%

module Fre_div_even(

	input clk,
	input rst_n,
	input [3:0] N, // N = 分频倍数/2
	output reg clk_out

    );


reg [3:0] cnt;


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        cnt <= 4'b0;
        clk_out <= 1'b0;
    end
    else
    begin
        if(cnt == N-1)
        begin
            clk_out <= ~clk_out;
            cnt <= 4'b0;
        end
        else
        begin
            cnt <= cnt + 4'b1;
        end
    end
end

endmodule

2. 奇数分频器

  • 奇数分频相对于偶数分频较为复杂,尤其是占空比为50%的奇数分频,可以采用错位相和的方法,即分别用上升沿和下降沿产生2:3占空比的N分频时钟,并将输出进行或运算得到
// 奇数分频器示例,5分频即N=5,占空比50%

module Fre_div_odd(
    input clk,
    input rst_n,
	input [3:0] N,  // N分频
    output clk_out
    );

reg clk_n;
reg clk_p;
reg [3:0] cnt_p;
reg [3:0] cnt_n;


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        clk_p <= 1'b0;
        cnt_p <= 4'b0;
    end
    else
    begin
        if(cnt_p == N-1)
        begin
            clk_p <= ~clk_p;
            cnt_p <= 4'b0;
        end
        else if(cnt_p == (N-1)/2)
        begin
            clk_p <= ~clk_p;
            cnt_p <= cnt_p + 1;
        end
        else
        begin
            cnt_p <= cnt_p + 1;
            clk_p <= clk_p;
        end
    end
end

always @(negedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        clk_n <= 1'b0;
        cnt_n <= 4'b0;
    end
    else
    begin
        if(cnt_n == N-1)
        begin
            clk_n <= ~clk_n;
            cnt_n <= 4'b0;
        end
        else if(cnt_n == (N-1)/2)
        begin
            clk_n <= ~clk_n;
            cnt_n <= cnt_n + 1;
        end
        else
        begin
            cnt_n <= cnt_n + 1;
            clk_p <= clk_p;
        end
    end
end

assign clk_out = clk_n | clk_p;


endmodule

3.半分频器

  • 在实际工程中,经常遇到需要半分频的情况,例如时钟晶振为25MHz,而我们需要用到2MHz的时钟信号,就需要进行12.5分频。
  • 半分频无法实现50%占空比,因为实现需要得到时钟信号的0.25周期,是无法实现的,因此只能使占空比尽量接近50%。
  • 半分频可以在奇数分频器额基础上实现,利用已经得到的奇数分频时钟信号将原时钟信号的后半段翻转;然后再对翻转后的波形计数,得到的波形与奇数分频得到的波形进行异或后即可得到需要的半分频时钟信号
  • 波形图如下:

// 半分频器示例,以2.5分频为例,即N=2

module Fre_div_half(
    input clk,
    input rst_n,
	input [3:0] N,  // 即实现N+0.5分频
    output clk_out
    );
	 

wire clk_div_odd;
wire clk_rev;

/*  按照上文的实现方法搭建奇数分频
    N_odd = 2 * N + 1             
    具体实现省略                  
    奇数分频后得到clk_div_odd     */
Fre_div_odd Fre_div_odd(
    .clk(clk),
    .rst_n(rst_n),
	.N(2*N+1),
    .clk_out(clk_div_odd)
    );	

	
assign clk_rev = clk_div_odd ? ~clk : clk;

reg [3:0] cnt_rev;
reg clk_rev_div; 

always @(posedge clk_rev or negedge rst_n)
begin
    if(!rst_n)
    begin
        clk_rev_div <= 0;
        cnt_rev <= 0;
    end
    else
    begin
		if(cnt_rev == N/2)
		begin
            clk_rev_div <= ~clk_rev_div;
			cnt_rev <= cnt_rev + 1;
		end
        else if(cnt_rev == N)
        begin
            cnt_rev <= 0;
        end
        else
        begin
            cnt_rev <= cnt_rev + 1;
            clk_rev_div <= clk_rev_div;
        end
    end
end

assign clk_out = clk_div_odd ^ clk_rev_div;


endmodule

仿真

  • 将三个分频器加入同一工程,并进行仿真
  • 顶层模块和testbunch代码如下
// 顶层模块,调用三种分频器模块

module Fre_div(

	input clk, 
	input rst_n,
	output clk_out_even,
	output clk_out_odd,
	output clk_out_half

    );

parameter N_even = 4;
parameter N_odd = 5;
parameter N_half = 3;
	
Fre_div_even Fre_div_even(

	.clk(clk),
	.rst_n(rst_n),
	.N(N_even),
	.clk_out(clk_out_even)

    );	

Fre_div_odd Fre_div_odd(
    .clk(clk),
    .rst_n(rst_n),
	.N(N_odd),
    .clk_out(clk_out_odd)
    );	
	
Fre_div_half Fre_div_half(
    .clk(clk),
    .rst_n(rst_n),
	.N(N_half),
    .clk_out(clk_out_half)
    );

endmodule
// 测试模块
module Fre_div_test; 

	// Inputs
	reg clk;
	reg rst_n;

	// Outputs
	wire clk_out_even;
	wire clk_out_odd;
	wire clk_out_half;

	// Instantiate the Unit Under Test (UUT)
	Fre_div uut (
		.clk(clk), 
		.rst_n(rst_n), 
		.clk_out_even(clk_out_even), 
		.clk_out_odd(clk_out_odd), 
		.clk_out_half(clk_out_half)
	);

	initial begin
		// Initialize Inputs
		clk = 1;
		rst_n = 1;
		

		// Wait 100 ns for global reset to finish
		#50;
		rst_n = 0;
		#50;
		rst_n = 1;
		
		forever	#50 clk = ~clk;
        
		// Add stimulus here

	end
      
endmodule
  • 仿真结果如下: 

猜你喜欢

转载自blog.csdn.net/stringYY/article/details/82900558