分配器原理及实现
分频器是指使输出信号频率为输入信号频率整数分之一的电子电路。在许多
电子设备中如电子钟、频率合成器等,需要各种不同频率的信号协同工作,常用
的方法是以稳定度高的晶振为主振源,通过变换得到所需要的各种频率成分,分
频器是一种主要变换手段。以下以 verilog HDL 语言为基础介绍占空比为 50%的
分频器。
一、偶分频
假设为 N 分频,只需计数到(N/2 – 1),然后时钟翻转同时计数清零,如此就
可以得到 N 分频。
二、奇分频
实现等占空比的奇数分频,需要使用两个时钟沿采样,上升沿和下降沿均需
计数到(N-1)/2 时,翻转时钟,并且计数到(N-1)时再次翻转时钟,然后将上升
沿和下降沿得到的两个波形进行或操作,便可以得到奇数 N 分频。三分频举例
如下图:
如果生成这样一个占空比为 2/3,周期为时钟 3 倍的信号,同时产生一个超
前或落后于它半个 clock 周期时间的信号,对两个信号进行相与,得到的结果恰
好就是三分频的时钟。
如果生成另外一个占空比为 1/3,周期为时钟 3 倍的信号,同时产生一个超
前或落后于它半个 clock 周期时间的信号,对两个信号相或,得到的结果恰好就
是三分频的时钟。
奇数分频的难点在于,三分频要求 1.5 倍的时钟时间翻转一次,这样整体的
周期时间是原来的 3 倍,即三分频,而 verilog 不允许在两个 always 模块里对同
一 reg 赋值。而且这里需要注意的是:在 FPGA 中的有关资料中,曾提到不要同
时使用时钟的上升沿和下降沿。对于奇数分频,需要同时使用到时钟的上升沿和
下降沿,解决方法有以下几种:
1)使用 PLL 得到 180 度反向时钟:先通过 PLL 锁相环产生两个频率相同、
相位差为 180 度的 clk1 和 clk2,然后在每个 clk 的上升沿进行采样。
2)使用 PLL 得到倍频信号:该信号上升沿可同时表示源时钟的上升沿和下
降沿,通过计数器的奇偶进行区分。
3)可以通过将 clk 简单取反得到一个新的 clk_180(clock_n),或者用全局
时钟资源中的 INV 来产生,之后通过 bufg 直接上全局时钟,时钟质量较好。
代码如下:
module divider
#(parameter DIV_CNT = 32'd1000)
(
input wire clk
input wire rst
output wire clk_div //输出分频后的时钟
);
,//输入时钟
,//输入复位信号
wire [31:0] div_cnt_even;//偶数分频系数
wire [31:0] div_cnt_odd;//奇数分频系数
wire odd;//奇数分频使能信号
assign odd = (DIV_CNT[0] == 1) ? 1'b1 : 1'b0;
assign div_cnt_even = (odd == 1'b1) ? (31'b0) :((DIV_CNT >> 1) - 1);
assign div_cnt_odd = (odd == 1'b1) ? ((DIV_CNT - 1) >> 1) :(31'b0);
reg [31:0] cnt_even ;
reg [31:0] cnt_odd_pos;
reg [31:0] cnt_odd_neg;
reg clk_div_even;
reg clk_div_odd_pos;
reg clk_div_odd_neg;
wire clk_div_odd;
assign clk_div_odd = clk_div_pos | clk_div_neg;
assign clk_div = (odd == 1'b1) ? clk_div_odd : clk_div_even;
wire clk_180;
assign clk_180 = ~clk;
//偶数分频电路
always @ (posedge clk or posedge rst)
if(rst)
clk_div_even <= 1'b0;
else if(div_cnt_even == 32'b0)
clk_div_even <= 1'b0;
else if(cnt_even == div_cnt_even)
clk_div_even <= ~clk_div_even;
always @ (posedge clk or posedge rst)
if(rst)
cnt_even <= 32'b0;
else if(div_cnt_even == 32'b0)
cnt_even <= 32'b0;
else if(cnt_even == div_cnt_even)
cnt_even <= 32'b0;
else
cnt_even <= cnt_even + 32'd1;
//奇数分频电路
always @ (posedge clk or posedge rst)
if(rst)
clk_div_odd_pos <= 1'b0;
else if(div_cnt_odd == 32'b0)
clk_div_odd_pos <= 1'b0;
else if(cnt_odd_pos == div_cnt_odd)
clk_div_odd_pos <= ~clk_div_odd_pos;
else if(cnt_odd_pos == DIV_CNT - 1)
clk_div_odd_pos <= ~clk_div_odd_pos;
always @ (posedge clk or posedge rst)
if(rst)
cnt_odd_pos <= 32'b0;
else if(div_cnt_odd == 32'b0)
cnt_odd_pos <= 32'b0;
else if(cnt_odd_pos == DIV_CNT - 1)
cnt_odd_pos <= 32'b0;
clk_div_odd_neg <= 1'b0;
else if(div_cnt_odd == 32'b0)
clk_div_odd_neg <= 1'b0;
else if(cnt_odd_neg == div_cnt_odd)
cnt_odd_pos <= cnt_odd_pos + 32'd1;
always @ (posedge clk_180 or posedge rst)
else
if(rst)
clk_div_odd_neg <= ~clk_div_odd_neg;
else if(cnt_odd_neg == DIV_CNT - 1)
clk_div_odd_neg <= ~clk_div_odd_neg;
always @ (posedge clk_180 or posedge rst)
if(rst)
cnt_odd_neg <= 32'b0;
else if(div_cnt_odd == 32'b0)
cnt_odd_neg <= 32'b0;
else if(cnt_odd_neg == DIV_CNT - 1)
cnt_odd_neg <= 32'b0;
else
cnt_odd_neg <= cnt_odd_neg + 32'd1;
//奇数分频电路 另外一种方法 例如三分频
endcase
state1 <= 2'b01;
if(rst)
else
begin
case(state1)
begin
2'b01:state1 <= 2'b10;
2'b10:state1 <= 2'b11;
2'b11:state1 <= 2'b01;
default:state2 <= 2'b01;
// assign clkout=state1[1]&state2[1];
// always@(posedge clk or posedge rst)
//
//
//
//
//
//
//
//
//
//
//
//
// always@(posedge clk_180 or posedge rst)
//
//
//
//
//
//
//
//
//
//
//
end
endmodule
2'b01:state2 <= 2'b10;
2'b10:state2 <= 2'b11;
2'b11:state2 <= 2'b01;
default:state2 <= 2'b01;
end
if(rst)
else
begin
state2 <= 2'b01;
case(state2)
endcase
PLL(Phase Locked Loop):锁相环,锁相环是一种反馈控制电路,利用外部
输入的参考信号控制环路内部振荡信号的频率和相位。