Verilog时钟分频(偶数分频、奇数分频、小数分频、半整数分频)

Verilog时钟分频(偶数分频、奇数分频、小数分频、半整数分频)

  • 偶数分频
  • 奇数分频
    • 不要求占空比为50%的奇数分频
    • 要求占空比为50%奇数分频
  • 小数分频
  • 半整数分频
    • 利用双边沿特性
    • 利用小数分频的思路

偶数分频

偶数分频最容易实现,可以用计数器实现。计数值小的时候也可以使用DFF直接完成。这里使用计数器实现,计数达到分频系数一半的时候进行翻转(占空比为50%)。对应: 牛客 VL37 时钟分频(偶数)

/**使用计数方式实现了8分频
*/
module even_div(input     wire  rstn,input     wire  clk,output    reg   clk_out
);reg [1:0] count;
/**count operation
*/
always @(posedge clk or negedge rstn) beginif(~rstn) begincount <= 2'b0;endelse begincount <= count + 1'b1;end
endalways @(posedge clk or negedge rstn) beginif(~rstn) beginclk_out <= 1'b0;endelse if(count == 2'b00) beginclk_out <= ~clk_out;end
endendmodule

仿真结果如下
在这里插入图片描述

奇数分频

不要求占空比为50%的奇数分频

不要求占空比为50%,可以与偶数分频一样,根据计数值进行波形翻转。
对应: 牛客 VL42 无占空比要去的奇数分频

/**不要求占空比的奇数分频5分频 3低电平2高电平占空比 2/5
*/
module odd_div (    input     wire rstn,input     wire clk,output    reg clko
);parameter N = 5;reg [2:0] count;
always @(posedge clk or negedge rstn) beginif(~rstn) begincount <= 3'd0;endelse if(count == N - 1) begincount <= 3'd0;endelse begincount <= count + 1'b1;end 
endalways @(posedge clk or negedge rstn) beginif(~rstn) beginclko <= 1'b0;endelse if(count == N - 1 || count == (N >> 1)) beginclko <= ~clko;endelse beginclko <= clko;end
endendmodule

仿真结果如下
在这里插入图片描述

要求占空比为50%奇数分频

无法单纯使用计数方式来实现,可以利用时钟双边沿特性产生两个占空比不为50%的时钟,然后将这两个时钟信号相与或者相或产生。

比如产生占空比为50%的5分频时钟,可以通过:

  1. 沿源时钟上升沿变化的,2cycle高电平,3cycle低电平,周期为5的时钟信号。
  2. 沿源时钟下降沿变化的,2cycle高电平,3cycle低电平,周期为5的时钟信号。
  3. 将上述两时钟信号相或得到占空比为50%的5分频时钟。

或者

  1. 沿源时钟上升沿变化的,3cycle高电平,2cycle低电平,周期为5的时钟信号。
  2. 沿源时钟下降沿变化的,3cycle高电平,2cycle低电平,周期为5的时钟信号。
  3. 将上述两时钟信号相与得到占空比为50%的5分频时钟。
/**产生	50%占空比 5分频的时钟1. 沿源时钟上升沿变化的,3cycle高电平,2cycle低电平,周期为5的时钟信号。2. 沿源时钟下降沿变化的,3cycle高电平,2cycle低电平,周期为5的时钟信号。3. 将上述两时钟信号相与得到占空比为50%的5分频时钟。
*/
module odd_div1(input       clk,input       rstn,output      clko
);parameter N = 5;reg [2:0] count;// 沿时钟上升沿变化的时钟信号 2低3高reg clkp;// 沿时钟下降沿变化的时钟信号reg clkn;assign clko = clkp & clkn;always @(posedge clk or negedge rstn) beginif(~rstn) begincount <= 3'b0;endelse if(count == N - 1) begincount <= 3'b0;endelse begincount <= count + 1'b1;endendalways @(posedge clk or negedge rstn) beginif(~rstn) beginclkp <= 1'b0;endelse if(count == 3'b1 || count == N - 1) beginclkp = ~clkp;endelse beginclkp <= clkp;endendalways @(negedge clk or negedge rstn) beginif(~rstn) beginclkn <= 1'b0;endelse if(count == 3'b1 || count == N - 1) beginclkn = ~clkn;endelse beginclkn <= clkn;endendendmodule

仿真波形如下
在这里插入图片描述

小数分频

对应 牛客 VL41 任意小数分频

无法做到占空比为50%的小数分频,也无法做到分频后的每个时钟周期都是原时钟周期的小数倍(当然如果是x.5是可以做到的)。
因此转换思路,进行7.6倍分频可以理解成分频后的时钟周期 To = 7.6T ,那么 10To = 76T,也就是说只要满足76个原时钟周期等于10个分频后的时钟周期即可。
这时候我们使用7分频和8分频的时钟来实现7.6倍分频的时钟,假设 10个分频后的时钟 由N个7分频的时钟和M个8分频的时钟组成,那么可以得到

	M + N = 10N7T + M8T = 76T⇒ M + N = 107N + 8M = 76

可以得到N = 4, M = 6。
就是由4个7分频的时钟和6个8分频的时钟组成7.6倍分频的时钟。
那么可以有四种方法将这两种时钟进行混合:

1. 先4次7分频再进行6次8分频
2. 先6次8分频再进行4次7分频
3. 将6次8分频插入4次7分频中
4. 将4次7分频插入6次8分频中
/**实现8.7倍分频由3个8分频和7个9分频时钟组成10个分频后的时钟=》24个原时钟周期用于8分频63个原时钟周期用于9分频先进行 3次8分频 再进行 7次9分频
*/module div_M_N(input  wire clk_in,input  wire rst,output wire clk_out
);/*8N + 9M = 87N + M = 10M = 7, N = 3因此3个8分频时钟 和 7个9分频时钟构成 8.7分频时钟
*/    /*3*8 = 24 87个原时钟周期里前24个周期 用来8分频7*9 = 63后63个时钟周期 用来9分频相当于10个8.7分频的时钟,前3个分频后的时钟周期由8分频组成,后7个由9分频组成
*/
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期reg clk_div;
assign clk_out = clk_div;// 计数87
reg [6:0] cnt87;
// 计数8
reg [2:0] cnt8;
// 计数9
reg [3:0] cnt9;always @(posedge clk_in or negedge rst) beginif(~rst) begincnt87 <= 7'b0;endelse if(cnt87 == M_N - 1'b1) begincnt87 <= 7'b0;endelse begincnt87 <= cnt87 + 1'b1;end   
end/*8/9分频时钟切换
*/
always @(posedge clk_in or negedge rst) beginif(~rst) begincnt8 <= 3'b0;cnt9 <= 4'b0;end// 8分频else if(cnt87 < c89) begincnt9 <= 4'b0;cnt8 <= cnt8 + 1'b1;end// 9分频else begincnt8 <= 3'b0;if(cnt9 == div_o - 1) begincnt9 <= 4'b0;endelse begincnt9 <= cnt9 + 1'b1;endend
endalways @(posedge clk_in or negedge rst) beginif(~rst) beginclk_div <= 1'b0;end// 8分频else if(cnt87 < c89) beginif (cnt8 == 3'b0 || cnt8 == 3'b100) beginclk_div <= ~clk_div;end   else beginclk_div <= clk_div;endend// 9分频else begin// 4高5低if (cnt9 == 3'b0 || cnt9 == 3'b100) beginclk_div <= ~clk_div;end   else beginclk_div <= clk_div;endend
endendmodule

仿真波形如下
在这里插入图片描述

半整数分频

半整数分频实际上就是特殊一点的小数分频,可以按照小数分频的方法完成,也可以利用时钟的双边沿特性完成。

利用双边沿特性

假设要进行5.5倍分频,那么让分频后的时钟信号2.5个原周期为高电平,3个原时钟周期为低电平。这样的信号要由两个沿不同时钟沿变化的信号产生:

  1. 由5时钟周期(沿上升沿变化,2周期高电平,3周期低电平)和6时钟周期的信号(沿上升沿变化,2周期高电平,4周期低电平)组成。
  2. 由5时钟周期(沿下降沿变化,2周期高电平,3周期低电平)和6时钟周期的信号(沿下降沿变化,2周期高电平,4周期低电平)组成。
  3. 将信号1和信号2相或得到 5.5倍分频的信号。
module half_int_div(input  wire clk,input  wire rstn,output wire clko
);reg clkp;reg clkn;assign clko = clkp | clkn;reg [3:0] cnt;always @(posedge clk or negedge rstn) beginif(~rstn) begincnt <= 4'b0;endelse if(cnt == 4'b1010) begincnt <= 4'b0;endelse begincnt <= cnt + 1'b1;endendalways @(posedge clk or negedge rstn) beginif(~rstn) beginclkp <= 1'b0;endelse if(cnt == 4'd0 || cnt == 4'd1 || cnt ==  4'd6 || cnt ==  4'd7) beginclkp <= 1'b1;endelse beginclkp <= 1'b0;endendalways @(negedge clk or negedge rstn) beginif(~rstn) beginclkn <= 1'b0;endelse if(cnt == 4'd1 || cnt == 4'd2 || cnt ==  4'd6 || cnt ==  4'd7) beginclkn <= 1'b1;endelse beginclkn <= 1'b0;endendendmodule

仿真波形如下
在这里插入图片描述

利用小数分频的思路

假设要进行5.5倍分频,相当于在11个原时钟周期里进行了两次5.5分频。采用5分频和6分频来实现5.5分频。那么

	5N + 6M = 11N + M = 2=>N = 1, M = 1

也就是说在11个原时钟周期里进行了一次5分频和一次6分频。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部