分频器——(任意奇分频(50%占空比、非50%占空比),任意偶分频,任意小数分频)

分频器定义:

        在数字系统的设计中经常会碰到需要使用多个时钟的情况。时钟信号的产生通常具有两种方法,一种是使用PLL(Phase Locked Loop,锁相环),可生成倍频、分频信号;另一种则是使用硬件描述语言构建一个分频电路。

        分频器的设计通常分为以下三类:奇数分频器、偶数分频器及小数分频器

偶分频:

        假设原来的时钟为clk,N(N为偶数)分频之后的时钟为clk_N,则N分频就是把原来的N个时钟周期变成现在的一个时钟周期。

        上图为8分频时序变化,8分频的时钟周期变为原来的分频前时钟的8倍,高电平占中时钟周期的一半,为50%占空比。

2.1verliog

根据上图可以编写任意偶数N分频Verilog代码如下:

        对于实现占空比为50%的N倍偶数分频,首先进行上升沿触发进行模N计数,计数选定到某一个值进行输出时钟翻转,然后经过(N>>1)-1再次进行一次时钟翻转。

2.1.1  复位之后先是低电平都是高电平的分频器

else  if(cnt ==((N>>1)-1) || cnt==(N-1))  		//N/2个时钟周期翻转一次
		clk_N <= ~clk_N;        //计满则输出反转

 2.1.2复位之后先是高电平再是低电平的分频器

//N分频电路设计
module divider_N                //模块名
(
	input		sys_clk,	    //时钟(设定为 50MHz)
	input		sys_rst_n,	    //复位信号(n 表示低电平有效)
	
	output	reg	clk_N		    //输出N分频信号
);
 parameter N==8;//例如N=8
reg [6:0]	cnt;                //reg 定义  
 
//计数模块
//从0计数到N-1共计N个时钟周期
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cnt <= 7'd0;			//复位清零
	else if(cnt == (N-1))		//从0开始计数,所以需要 -1
		cnt <= 7'd0;			//计满则清零
	else
		cnt <= cnt + 7'd1; 		//没记满就一直计数
end
 
//N分频时钟输出模块
//满足计数条件则对N分频时钟进行反转
//N分频时钟每隔N/2个周期反转一次,所以N分频的周期即为N个时钟周期
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)                  
		clk_N <= 1'b0;          //复位清零
	else  if(cnt ==0 || cnt==((N>>1)-1))  		//N/2个时钟周期翻转一次
		clk_N <= ~clk_N;        //计满则输出反转
    else
        clk_N <= ~clk_N;        //未计满则保持

end

endmodule

        以上两类在实际运用中并无区别,只不过在牛客网一些测试题中进行了区分。

2.1.3:关于计数器的问题,若复位时刻恰在时钟的上升沿,由于FPGA的并行性质,上升沿采样时的rst_n==0, 因此该时钟周期的cnt==0,rst_n==1。

        

 上图就可以很好的解释,复位之后计数器的初始值为0,在时钟的上升沿,cnt立即变为(陡变)cnt==1。

这就说明假如复位信号提前,cnt实际上是从cnt==1开始计数的。

奇分频:

        奇分频的含义即为分频数如:3、5、7、9之类奇数数字的分频器,由于奇数无法被2整除,例如在7分频中,奇数分频就会出现占空比为50%的7分频器,高低电平各占3.5个周期。

50%占空比奇分频实现方法

        对于实现占空比为50%的N倍奇数分频,首先进行上升沿触发进行模N计数,计数选定到某一个值进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比非50%奇数n分频时钟。

        同时进行下降沿触发的模N计数,到和上升沿触发输出时钟翻转选定值相同值时,进行输出时钟时钟翻转,同样经过(N-1)/2时,输出时钟再次翻转生成占空比非50%的奇数n分频时钟。

        两个占空比非50%的n分频时钟相或运算,得到占空比为50%的奇数n分频时钟。

`timescale 1ns/1ns

module odo_div_or
   (
    input    wire  rst ,
    input    wire  clk_in,
    output   wire  clk_outN
    );

//*************code***********//

    reg clk_neg, clk_pos;
    reg [5:0] cnt;
    
    always@(posedge clk_in or negedge rst) begin//计数器
        if(~rst)
            cnt <= 0;
        else
            cnt <= cnt==(N-1)? 0: cnt+1;
    end
    
    always@(posedge clk_in or negedge rst) begin//上升沿翻转
        if(~rst)
            clk_pos <= 0;
        else
            clk_pos <= (cnt==((N-1)>>1)||cnt==(N-1))? ~clk_pos: clk_pos;
    end
    
    always@(negedge clk_in or negedge rst) begin//下降沿翻转
        if(~rst)
            clk_neg <= 0;
        else
            clk_neg <= (cnt==((N-1)>>1)||cnt==(N-1))? ~clk_neg: clk_neg;
    end

    assign clk_outN = clk_neg|clk_pos;
//*************code***********//
endmodule


        

任意占空比奇分频:

        对于实现占空比为50%的N倍奇数分频,首先进行上升沿触发进行模N计数,计数选定到某一个值进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比非50%奇数n分频时钟。

这样就得到了一个占空比为为(N-1)/2 /N的奇分频时钟。


任意小数分频

                假设输出clk_out是输入clk_in的N分频。首先要将分频系数N化为分数形式,比如3.4→34/10​。本题中,8.7可以化为87/10。这意味着在87个clk_in周期内输出10个clk_out周期就可以实现分频。

 

        然后采用若干种(一般是两种)整数分频在87个原周期clk_in内产生10个新时钟周期clk_out。整数分频的分频系数有很多种选择,但要尽可能接近,提高clk_out的均匀度。一般推荐在小数分频系数N的附近选取。因为8<N<9,所以两个整数分频系数是8和9。接着要计算87个clk_out周期分别有多少个是8分频和9分频的。设每10个clk_out中有x个8分频输出和y个9分频输出,则可列出如下方程:

 

可得x=3,y=7。也就是3个8分频和7个9分频一组,循环输出,就等效于8.7分频。 最后安排组内8分频和9分频的位置。这里的方法也不固定,不过本题要求3个8分频先输出,再输出7个9分频,如下图。

 

        3个8分频先输出,再输出7个9分频

`timescale 1ns/1ns

module div_M_N(
 input  wire clk_in,
 input  wire rst,
 output wire clk_out
);
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
reg [7:0] cnt;

reg [4:0] cnt1,cnt2;

reg clk1, clk21, clk22;

wire clk_2;


always@(posedge clk_in or negedge rst)//89计数器
    if(!rst)
        cnt<=0;
    else 
        cnt<= (cnt==(M_N-1))? 0: cnt+1;


always@(posedge clk_in or negedge rst)//计数器
    if(!rst)
        cnt1<=0;
    else if(cnt<=c89)
        cnt1<=(cnt1==5'd7)? 0 : cnt1+1;
    else
        cnt1<=0;

always@(posedge clk_in or negedge rst)//偶数8分频
    if(!rst)
        clk1<=0;
    else 
        if(cnt1 == 3'b0 || cnt1 == div_e / 2)
            clk1<=~clk1;
        else
            clk1<=clk1;
    
always@(posedge clk_in or negedge rst)//奇数分频计数器
    if(!rst)
        cnt2<=0;
    else if(cnt>=c89)
        cnt2<=(cnt2==5'd8)? 0 : cnt2+1;
    else
        cnt2<=0;


always@(posedge clk_in or negedge rst)//奇数分频
    if(!rst)
        clk21<=0;
    else
        if(cnt2 == 4'b0 || cnt2 == (div_o - 1'b1) / 2)
            clk21<=~clk21;
        else
            clk21<=clk21;


assign clk_out = (cnt <= c89 )? clk1 : clk21;

            

//*************code***********//
endmodule

         以上就是任意偶数分频器,奇数分频器,小数分频器的知识点,其简单来说都是计数器+时钟翻转电路的两部分组成。

        以上代码N经过替换之后是可以直接使用的,希望大家可以多多点赞支持。

  • 10
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值