偶分频与奇分频小结

前言

由于FPGA只有一个晶振产生时钟,然而实际项目中需要用到不同频率的时钟信号,这个时候就需要进行分频与倍频,产生分频方式有两种:使用PLL核verilog代码自己实现;而倍频我们只能通过PLL核来实现

偶分频

首先以一个六分频为例来向大家讲解。

通过Visio 2013绘制的原理图如下

 假设原来的时钟是sys_clk,复位信号是sys_rst_n,计数器为cnt,六分频之后的时钟为clk_flag,则六分频就是把原来的六个时钟周期变成现在的一个时钟周期。cnt计数范围0~5,占空比是1:6

可以设clk_flag的低电平对应cnt的0~4,高电平对应5,分频之后clk_flag由低电平变为高电平的时刻是clk_flag为4时。

当我们要产生任意偶分频时,我们假设分频系数为DIV_CLK_FACTOR,也就是我们要几分频,计数器仍然为cnt,并且cnt的初始值为0。基于上面的分析,可以知道,当cnt计数到DIV_CLK_FACTOR-1时,恰好是我们所需要的时钟的一个周期。至于clk_flag何时拉高,要根据占空比确定,当cnt计数到DIV_CLK_FACTOR*(1-占空比)-1时,将clk_flag拉高,当cnt计数到0时,将clk_flag拉低,之所以这样,是因为方便代码的编写,此公式适合于任何占空比。

下面通过代码分析

module    divider_six
(
  input   wire     sys_clk,
  input   wire     sys_rst_n,
  
  output  reg      clk_flag
);

reg   [2:0]   cnt;

//分频计数器计数
always@(posedge sys_clk or negedge sys_rst_n)
       if(sys_rst_n == 1'b0)
	       cnt <= 3'd0;
	   else  if(cnt == 3'd5)
	       cnt <= 3'd0;
	   else 
	       cnt <= cnt + 3'd1;

//分频
always@(posedge sys_clk or negedge sys_rst_n)
       if(sys_rst_n == 1'b0)
           clk_flag  <= 1'b0;
       else  if(cnt == 3'd4)
           clk_flag  <= 1'b1;
       else
           clk_flag  <= 1'b0;

endmodule

仿真代码:

`timescale  1ns/1ns
module   tb_divider_six();

reg sys_clk;
reg sys_rst_n;

wire   clk_flag;

initial
     begin
	     sys_clk = 1'b1;
		 sys_rst_n <= 1'b0;
		 #20
		 sys_rst_n <= 1'b1;
	 end
	 
always #10 sys_clk = ~sys_clk;

divider_six   divider_six_inst
(
  .sys_clk    (sys_clk),
  .sys_rst_n  (sys_rst_n),
             
  .clk_flag    (clk_flag)
);

endmodule

仿真波形图如下:

 偶分频还可以另外一种方法

此种方法只适合于产生占空比50%的偶分频,同样以六分频为例

通过Visio 2013绘制的原理图如下

 cnt计数范围是0~DIV_CLK_FACTOR/2-1,当计数器cnt计数到DIV_CLK_FACTOR/2-1时,clk_out电平发生翻转,此时产生的占空比就是50%

代码如下

module    divider_six
(
  input   wire     sys_clk,
  input   wire     sys_rst_n,
  
  output  reg      clc_out
);

reg   [2:0]   cnt;

//分频计数器计数
always@(posedge sys_clk or negedge sys_rst_n)
       if(sys_rst_n == 1'b0)
	       cnt <= 2'd0;
	   else  if(cnt == 2'd2)
	       cnt <= 2'd0;
	   else 
	       cnt <= cnt + 2'd1;

//分频
always@(posedge sys_clk or negedge sys_rst_n)
       if(sys_rst_n == 1'b0)
	       clc_out <= 1'b0;
	   else  if(cnt == 2'd2)
	       clc_out <= ~clc_out;
       else
           clc_out <= clc_out;

endmodule

仿真波形图如下

 仿真代码如下

`timescale  1ns/1ns
module   tb_divider_six();

reg sys_clk;
reg sys_rst_n;

wire   clc_out;

initial
     begin
	     sys_clk = 1'b1;
		 sys_rst_n <= 1'b0;
		 #20
		 sys_rst_n <= 1'b1;
	 end
	 
always #10 sys_clk = ~sys_clk;

divider_six   divider_six_inst
(
  .sys_clk    (sys_clk),
  .sys_rst_n  (sys_rst_n),
             
  .clc_out    (clc_out)
);

endmodule

奇分频

以5分频为例

占空比2:3时,原理图如下

 其中sys_clk为系统时钟,cnt为计数器,clk_out为输出信号,clk_1、clk_2分别为上升沿和下降沿翻转产生的中间时钟,clk_out = (clk_1 | clk_2),因此clk_1、clk_2的电平跳变时刻需要根据clk_out来确定。

代码如下

module divider_five
(
    input   wire    sys_clk,
	input   wire    sys_rst_n,
	
	output  wire    clc_out
);

reg    [2:0]   cnt;
reg            clk_1;
reg            clk_2;

//分频计数器计数
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
		     cnt <= 3'd0;
		else  if(cnt == 3'd4)
		     cnt <= 3'd0;
		else
		     cnt <= cnt + 3'd1;

//分频
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
		     clk_1 <= 1'b0;
		else  if(cnt == 3'd2)
		     clk_1 <= 1'b1;
		else  if(cnt == 3'd4)
		     clk_1 <= 1'b0;
		else
		     clk_1 <= clk_1;
		
always@(negedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
		     clk_2 <= 1'b0;
        else  if(cnt == 3'd2)	
             clk_2 <= 1'b1;
        else  if(cnt == 3'd4)
             clk_2 <= 1'b0;
        else
             clk_2 <= clk_2;

assign  clc_out = (clk_1 | clk_2);

endmodule

仿真波形图如下

 仿真代码如下

`timescale  1ns/1ns
module   tb_divider_five();

reg sys_clk;
reg sys_rst_n;

wire   clc_out;

initial
     begin
	     sys_clk = 1'b1;
		 sys_rst_n <= 1'b0;
		 #20
		 sys_rst_n <= 1'b1;
	 end
	 
always #10 sys_clk = ~sys_clk;

divider_five   divider_five_inst
(
  .sys_clk    (sys_clk),
  .sys_rst_n  (sys_rst_n),
             
  .clc_out    (clc_out)
);

endmodule

其它占空比的奇分频的设计如下

其实和偶分频套路一样,代码如下

module divider_five
(
    input   wire    sys_clk,
	input   wire    sys_rst_n,
	
	output  reg    clk_flag
);

reg    [2:0]   cnt;

//分频计数器计数
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
		     cnt <= 3'd0;
		else  if(cnt == 3'd4)
		     cnt <= 3'd0;
		else
		     cnt <= cnt + 3'd1;

//分频
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)	
             clk_flag  <= 1'b0;
		else  if(cnt == 3'd3)
		     clk_flag  <= 1'b1;
		else
		     clk_flag  <= 1'b0;

endmodule

 仿真波形图如下

 任意分频的参考下面的博客

参考:奇分频和偶分频_dongtao Lv的博客-CSDN博客_奇分频和偶分频

           任意整数分频(图文并茂)_dongtao Lv的博客-CSDN博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值