FPGA时钟分频的几种方法

本文详细介绍了在FPGA中实现时钟分频的多种方法,包括定义分频参数、直接计算计数值进行偶数分频、奇数分频、使用PLL以及提供一种奇偶分频通用程序。通过具体的Verilog代码示例,展示了如何根据不同的需求选择合适的分频策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.定义分频参数

localparam  CLK_DIVIDE = 4'd10     ;        // 时钟分频系数

reg    [ 3:0]             clk_cnt  ;        // 时钟分频计数器
reg                       dri_clk  ;        // 数码管的驱动时钟

always @(posedge clk or negedge rst_n) begin
  if(!rst_n) begin
      clk_cnt <= 4'd0;
      dri_clk <= 1'b1;
  end
  else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
      clk_cnt <= 4'd0;
      dri_clk <= ~dri_clk;
  end
  else begin
      clk_cnt <= clk_cnt + 1'b1;
      dri_clk <= dri_clk;
  end
end 

2.直接计算cnt计数值

reg    [11:0]   div_cnt        ;  //分频计数器
reg             div_clk        ;  //分频时钟

时钟分频,50Mhz/(2*(3124+1))=8khz,T=0.125ms
always @(posedge sys_clk or negedge sys_rst_n  ) begin
   if (!sys_rst_n) begin
       div_cnt <= 12'd0;
       div_clk <= 1'b0;
   end    
   else if(div_cnt == 12'd3124) begin
       div_cnt <= 12'd0;
       div_clk <= ~div_clk;
   end    
   else
       div_cnt = div_cnt + 12'b1;
end

cnt的计算是用sysclk除以需要的频率,得到cnt_total,cnt_total除以2再减1就是cnt的值。

assign  clk_divide = (CLK_FREQ/I2C_FREQ) >> 2'd3;// 模块驱动时钟的分频系数

//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        dri_clk <=  1'b1;
        clk_cnt <= 10'd0;
    end
    else if(clk_cnt == clk_divide - 1'd1) begin
        clk_cnt <= 10'd0;
        dri_clk <= ~dri_clk;
    end
    else
        clk_cnt <= clk_cnt + 1'b1;
end

右移3位,这个程序中相对于I2C_FREQ时钟频率*8,但是少了上面除以2的操作,所以最后是四倍I2C_FREQ。因为我们操作的是时钟取反需要计数到的值,和我们平时接触到的直接改变数字大小是反着的

3.奇数分频

上面的1和2适合偶数分频,奇数分频采用下面方法

//7分频,奇数分频都可以类似这么做,只需要改div1和div2的参数。
//div1为奇数分频除2的整数部分,div2为分频系数减1。
//采用上升延和下降延分别触发不同波形,最后叠加的方式产生奇数分频。
module odd_div(clk, clk1x, rst, clk1xpose, clk1xnege, coutpose, coutnege);  
input clk;  
input rst;  
output clk1x;  
output clk1xpose;  
output clk1xnege;  
output[2:0] coutpose;  
output[2:0] coutnege;
  
reg clk1xpose;  
reg clk1xnege;  
reg[2:0] coutpose;  
reg[2:0] coutnege;  

parameter div1 = 3 , div2 = 6;  // div1 = 7 / 2, div2 = 7 - 1  
assign clk1x = clk1xpose | clk1xnege;  

always@(posedge clk or negedge rst)  
begin  
  if(!rst)  
    clk1xpose <= 0;  
  else if(coutpose == div1)  
    clk1xpose <= ~clk1xpose;  
  else if(coutpose == div2)  
    clk1xpose <= ~clk1xpose;  
  else   
    clk1xpose <= clk1xpose;  
end 
 
always@(negedge clk or negedge rst)  
begin  
  if(!rst)  
    clk1xnege <= 0;  
  else if(coutnege == div1)  
   clk1xnege <= ~clk1xnege;  
  else if(coutnege == div2)  
   clk1xnege <= ~clk1xnege;  
  else   
   clk1xnege <= clk1xnege;  
end  

always@(posedge clk or negedge rst)  
begin  
  if(!rst)  
		coutpose <= 0;  
	else if(coutpose < div2)  
		coutpose <= coutpose + 1;  
  else  
		coutpose <= 0;  
end  

always@(negedge clk or negedge rst)  
begin  
  if(!rst)  
		coutnege <= 0;  
  else if(coutnege < div2)  
		coutnege <= coutnege + 1;
  else  
		coutnege <= 0;  
end  

endmodule  

采用计数的方法分频,理论上看起来没什么问题,但实际应用中,时钟偏移有点严重,所以最好还是用PLL,但对时钟要求不是很精确时可以用计数的方法。下图是程序的时序仿真波形。
在这里插入图片描述

4.PLL

5.奇偶分频通用程序

//N是分频系数,WIDTH要大于等于能够表示N的位数
module clk_divide
    #(
    parameter			WIDTH	=	3,
	parameter			N		=	5
    )(
	//INPUT
	input      clk,
	input      rst_n,
	//OUTPUT
	output     clkout			
);

	//********************
	//REGS
	reg 	[WIDTH-1:0]		cnt_p,cnt_n;
	reg						clk_p,clk_n;
 
	assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p;
 
	//Sequential logic style
	always @ (posedge clk)
		begin
			if(!rst_n)
				cnt_p<=0;
			else if (cnt_p==(N-1))
				cnt_p<=0;
			else cnt_p<=cnt_p+1;
		end
 
	always @ (negedge clk)
		begin
			if(!rst_n)
				cnt_n<=0;
			else if (cnt_n==(N-1))
				cnt_n<=0;
			else cnt_n<=cnt_n+1;
		end
 
	always @ (posedge clk)
		begin
			if(!rst_n)
				clk_p<=0;
			else if (cnt_p<(N>>1))  
				clk_p<=0;
			else 
				clk_p<=1;
		end
 
	always @ (negedge clk)
		begin
			if(!rst_n)
				clk_n<=0;
			else if (cnt_n<(N>>1))  
				clk_n<=0;
			else 
				clk_n<=1;
		end
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值