# 基于Verilog的偶数、奇数、半整数分频以及任意分频器设计

1.偶数分频器

`module clk_div(clk_out, clk, rst_n);input clk, rst_n;output clk_out;reg clk_out;reg [4:0] cnt;always @(posedge clk or negedge rst_n)if(!rst_n)begin cnt <= 5'b0;clk_out <= 1'b0;endelse if(cnt == 4'd9)begin cnt <= 5'b0;clk_out <= ~clk_out;endelse cnt <= cnt + 1'b1;endmodule`
` `
`2.奇数分频器`
` `

` `
`奇数分频器示例，5分频，占空比50%`

`module div_odd(input clk,input rst_n,output clk_out);//----------count the posedge---------------------reg [2:0] cnt_p;reg clk_p;always @ (posedge clk or negedge rst_n)if(!rst_n)cnt_p <= 3'd0;else if(cnt_p == 3'd4)cnt_p <= 3'd0;elsecnt_p <= cnt_p + 1'b1;always @ (posedge clk or negedge rst_n)if(!rst_n)clk_p <= 1'b0;else if((cnt_p == 3'd2) || (cnt_p == 3'd4))clk_p <= ~ clk_p;//---------------------------------------------//----------count the negedge------------------reg [2:0] cnt_n;reg clk_n;always @ (negedge clk or negedge rst_n)if(!rst_n)cnt_n <= 3'd0;else if(cnt_n == 3'd4) cnt_n <= 3'd0;else cnt_n <= cnt_n + 1'b1;always @ (negedge clk or negedge rst_n)if(!rst_n)clk_n <= 1'b0;else if((cnt_n == 3'd2) || (cnt_n == 3'd4))clk_n <= ~clk_n;//----------------------------------------------assign clk_out = clk_p | clk_n;endmodule`

here is the old version :

`module div_odd(clk_out, clk, rst_n);input clk, rst_n;oput clk_out;reg clk_p, clk_n;reg [4:0] cnt1, cnt2; //注意根据实际需要调整位宽parameter N = 5; //此处N可以设为任意奇数//用上升沿产生非50%占空比的分频信号clk_palways @(posedge clk or negedge rst_n)if(!rst_n)begin cnt1 <= 0;clk_p <= 0;endelse if(cnt1 == 5'b10) //cnt_p == (N-1)/2，翻转begin cnt1 <= cnt1 + 1'b1;clk_p <= ~clk_p;endelse if(cnt1 == 5'b100) //cnt_p == N-1，翻转begin cnt1 <= 1'b0;clk_p <= ~clk_p;endelse cnt1 <= cnt1 +1'b1;//用下降沿产生非50%占空比的分频信号clk_nalways @(negedge clk or negedge rst_n)if(!rst_n)begin cnt2 <= 0;clk_n <= 0;endelse if(cnt2 == 5'b10) //cnt_n == (N-1)/2，翻转begin cnt2 <= cnt2 + 1'b1;clk_n <= ~clk_n;endelse if(cnt2 == 5'b100) //cnt_n == N-1，翻转begin cnt2 <= 1'b0;clk_n <= ~clk_n;endelse cnt2 <= cnt2 +1'b1;//相与运算，得到50%占空比的分频信号assign clk_out = clk_p | clk_n;endmodule`
`3.半分频器（N+0.5分频）`
` 在实际工程中，我们还经常会遇到半分频器。比如要得到2MHz的时钟信号，而系统晶振频率为25MHz，这时候就需要对系统时钟作12.5分频。那么这种半分频器又该如何实现呢？最直接的办法当然还是用计数器了，由于半整数分频无法实现50%的占空比（因为50%占空比就要求一个周期内高低电平都是6.25个系统时钟周期，这个0.25是不可能实现的），我们只能让占空比尽可能接近50%。以12.5分频为例，可以对系统时钟计数，在前6.5个周期输出低电平，后6个周期输出高电平，依次循环，就可以实现12.5分频，占空比为（6.5/12.5)，接近50%。在计数时涉及到0.5个周期，因此对上升沿和下降沿都要计数。具体代码如下：`
` `
`半分频器，以12.5分频为例，占空比（6.5/12.5）`

`module clk_half(clk_out, clk1, clk, rst_n);input clk,rst_n;output clk_out,clk1;parameter N = 13; //以12.5分频为例，N=13wire clk1;reg clk_out;reg[4:0] cnt;reg flag = 1'b0;//系统时钟clk计数器always @(negedge clk or negedge rst_n)if(!rst_n) flag <= 1'b0;else if(cnt == 5'd6) flag <= ~flag;//在第五个时钟结束后立即将 clk1 状态翻转assign clk1 = (flag)? ~clk:clk;//时钟 clk1 计数器，模为Nalways @(posedge clk1 or negedge rst_n)if(!rst_n) cnt <= 5'b0;else if(cnt == 5'd12) cnt <= 5'b0;else cnt <= cnt + 1'b1;//前6.5个周期为低电平，后6个周期为高电平，//即为12.5分频always @(posedge clk1 or negedge rst_n)if(!rst_n) clk_out <= 1'b0;else if(cnt == 5'd0) clk_out <= 1'b0;else if(cnt == 5'd7) clk_out <= 1'b1;else clk_out <= clk_out;endmodule`
`网上还有许多其他大神写的半分频程序，比如：`
`http://www.cnblogs.com/yuzeren48/p/3965003.html`
` `
`4.任意分频——基于相位累加原理`

` `
`任意分频示例，输出1kHz，占空比50%`

`/***************************************晶振频率 fc = 50MHz输出频率 fo = 1kHz（根据需要可以设为任意值）控制参数 K = (fo*2^N)/fc参数 N = 2^32,(32为计数器的位宽)****************************************/module div_free(clk_out, clk, rst_n);input clk, rst_n;output clk_out;reg clk_out;reg [31:0] cnt;always @(posedge clk or negedge rst_n)if(!rst_n)cnt <= 0;else cnt <= cnt + 32'd85900; //计数器步长 Kalways @(posedge clk or negedge rst_n)if(!rst_n)begin clk_out <= 1'b0;endelse if(cnt < 32'h7FFF_FFFF)clk_out <= 1'b0;else clk_out <= 1'b1;endmodule`

Top