FPGA分频电路实现(奇数,偶数,小数半分频,任意分频)

前言
虽然在实际工程中要产生分频时钟一般采用FPGA的时钟管理器来进行分频、倍频,通过设置一下IP核中的参数即可,这样做有很多别的方法(例如:直接用Verilog HDL设计分频电路)达不到的效果,产生时钟的质量也更好,因此,一般而言,也推荐这种方法,但这并非意味着直接用Verilog HDL设计分频电路一无是处,毫无用途。

由于FPGA的晶振频率都是固定值,只能产生固定频率的时序信号,但是实际工程中我们需要各种各样不同频率的信号,这时候就需要对晶振产生的频率进行分频。

如果对时钟的性能要求不高,我就自然就可以用这种方法产生分频时钟,这样就只消耗了少量的资源而实现了时钟的分频要求,我们把这种设计叫做分频器设计。

注意:分频电路可以这么设计,但倍频电路呢?恐怕写不出来吧!只能用IP核来产生

分频器分类
分频器分为偶分频、奇分频,下面分别介绍二者的设计原理。

1)偶分频

相信大多数朋友在学习FPGA过程中接触到的第一个实验应该就是偶数分频器了,偶数分频器的设计较为简单,用一个简单的计数器就可以实现。比如要实现一个N分频(N为偶数)的分频器,可以先写一个计数器,当计数到(N/2-1)时,让输出状态翻转,并将计数器清零,这样输出的信号就是输入时钟的N分频了。

N分频(N为偶数),计数器计数到N/2-1翻转。如进行4分频,count=4/2-1=1时翻转,6分频计数器计到2翻转。程序如下,经过实测验证,正确。

//偶分频电路的Verilog HDL设计(10分频为例)
module even_freq_div(clk, rst, clk_div10,cnt);
 
input clk;
input rst;
output clk_div10;
reg clk_div10;
output [2:0] cnt;          //输出cnt的原因是为了看到计数次数,便于分析仿真结果。
reg [2:0] cnt;
 
 
 
always @(posedge clk)
begin
	if(rst)  //复位信号有效;
	begin
		cnt <= 0;          //计数器清零
		clk_div10 <= 0;    //输出清零;
	end
	else     //复位信号无效;
	begin
		if(cnt == 4)                //每一次时钟上升沿到来时,都检查一次计数值是否达到4;
		begin
			clk_div10 <= ~clk_div10;
			cnt <= 0; //计数器计数到4后,重新清零;计数值为4意味着已经计了5个周期,这时10分频时钟翻转一次;
		end
		else     //如果计数器未计数到4,则来一个上升沿加1,同时分频时钟继续保持原值不变。
		begin
			cnt <= cnt + 1;           
			clk_div10 <= clk_div10;  //否则继续保持;
		end
	end
	
end
 
 
endmodule

2)奇分频

奇数分频器的设计比偶数分频器复杂一些,特别是占空比为50%的奇数分频器。如果对占空比没有明确的要求,则可以直接对上升沿计数,计数到(N-1)/2 时让输出翻转,计数到(N-1)时让输出状态再次翻转,并将计数器清零,这样就可以得到一个占空比为2:3的N分频(N为奇数)的分频器。而如果要实现50%的占空比,可以通过“错位相或”的方法实现。具体方法是用刚才的方法先通过对上升沿计数产生一个占空比为不是50%的N分频器,再用同样的方法对下降沿计数产生一个占空比也不是50%的N分频器,最后将这两个分频器的输出进行“或”运算,就可以得到占空比为50%的奇数N分频器,

以5分频为例,我们写一个Verilog程序:
 

`timescale 1ns / 1ps
//
// Company: 
// Engineer: CSDN 李锐博恩
// 
// Create Date: 2019/07/28 15:15:27
// Design Name: 
// Module Name: FRE_DIV5
 
//
 
 
module FRE_DIV5(
	input clk,
	input rst_n,
	output clk_div5
 
    );
	
	reg [2:0] div_cnt;
	
	always@(posedge clk or negedge rst_n) begin
		if(~rst_n) begin
			div_cnt <= 0;
		end
		else if(div_cnt <4) begin
			div_cnt <= div_cnt + 1;
		end
		else 
			div_cnt <= 0;
	
	end
	
	reg clk_div_r, clk_div_rr;
	
	always@(posedge clk or negedge rst_n) begin
		if(~rst_n) begin
			clk_div_r <= 1;
		end
		else if(div_cnt == 1) begin
			clk_div_r <= ~clk_div_r;
		end
		else if(div_cnt == 4) begin
			clk_div_r <= ~clk_div_r;
		end
		else	clk_div_r <= clk_div_r;
	end
	
	always@(negedge clk or negedge rst_n) begin
		if(~rst_n) begin
			clk_div_rr <= 1;
		end
		else clk_div_rr <= clk_div_r;
	end
	
	assign clk_div5 = clk_div_r | clk_div_rr;
	
	
endmodule

3.半分频器(N+0.5分频)

`timescale 1ns/1ps
///
//Create Date: 2020/03/05 
//Module Name: half_integer_div
//Engineer: hewen 
///
module half_integer_div(
	input clk,
	input rst_n,
	output clk_out
);

parameter N = 3;  //3.5分频

reg[31:0] cnt1;
reg clk_p;
reg clk_n;
always @(posedge clk or posedge rst_n)
begin
	if(!rst_n)
		cnt1<=0;
	else if(cnt1 == 2*N)
		cnt1<= 0;
	else
		cnt1<=cnt1+1;
end

always @(posedge clk or posedge rst_n)	
begin 
	if(!rst_n)
		clk_p<=0;
	else if(cnt1 == 2*N)
		clk_p<=1;
	else if(cnt1 == N)
		clk_p<=0;
end

always @(negedge clk or posedge rst_n)
begin
	if(!rst_n)
	clk_n <= 0;
	else if (cnt1==0)
		clk_n <= 0;
	else if(cnt1 ==N)
		clk_n<=1;
end

assign clk_out = clk_p & clk_n;
	
endmodule

4.任意分频

`timescale 1ns/1ps
///
//Create Date: 2020/03/05 
//Module Name: divide
//Engineer: hewen 
///
module divide #
(							
parameter WIDTH = 24, //计数器的位数,计数的最大值为 2**(WIDTH-1)
parameter N = 5  //分频系数,请确保 N<2**(WIDTH-1),否则计数会溢出
)
(input clk,  //clk连接到FPGA的C1脚,频率为12MHz
input rst_n,  //复位信号,低有效,
output clkout  //输出信号,可以连接到LED观察分频的时钟
); 
 reg [WIDTH-1:0] cnt_p,cnt_n;	
 reg clk_p,clk_n;	
 
/**********上升沿触发部分************/
//上升沿触发时计数器的控制
always @(posedge clk or negedge rst_n)	    
begin     
	if(!rst_n)
		cnt_p <= 1'b0;    
	else if(cnt_p == (N-1))
		cnt_p <= 1'b0;    
	else 
		cnt_p <= cnt_p + 1'b1;		    
end 
 //上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
always @(posedge clk or negedge rst_n)    
begin    
	if(!rst_n)
		clk_p <= 1'b0;    
	else if(cnt_p < (N>>1))	
		clk_p <= 1'b0;
	else 
		clk_p <= 1'b1;	
end

/***********下降沿触发部分*************/
//下降沿触发时计数器的控制        	
always @(negedge clk or negedge rst_n)    
begin    
	if(!rst_n)
		cnt_n <= 1'b0;    
	else if(cnt_n == (N-1))
		cnt_n <= 1'b0;    
	else 
		cnt_n <= cnt_n + 1'b1;
end  
//下降沿触发的分频时钟输出,和clk_p相差半个clk时钟
always @(negedge clk or negedge rst_n)    
begin    
	if(!rst_n)
		clk_n <= 1'b0;    
	else if(cnt_n < (N>>1))  
		clk_n <= 1'b0;   
	else 
		clk_n <= 1'b1;    
end
wire clk1 = clk;  //当N=1时,直接输出clk
wire clk2 = clk_p;  //当N为偶数也就是N[0]=0,输出clk_p
wire clk3 = clk_p & clk_n;  //当N为奇数也就是N[0]=1,输出clk_p&clk_n。正周期多所以是相与  
assign clkout = (N==1)? clk1:(N[0]? clk3:clk2);	
endmodule

 

  • 5
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值