分频器的 verilog
HDL 描述(转)
分频器,在许多涉及时序的电路设计中都会用到,在这里,我转载某位高人的文章,关于分频
器的设计
偶数倍分频:偶数倍分频应该是大家都比较熟悉的分频,通过计数器计数是完全可以实现的。
如进行 N 倍偶数分频,那么可以通过由待分频的时钟触发计数器计数,当计数器从 0 计数到
N/2-1 时,输出时钟进行翻转,并给计数器一个复位信号,使得下一个时钟从零开始计数。
以此循环下去。这种方法可以实现任意的偶数分频。
module odd_division(clk,rst,count,clk_odd);
input
output
clk,rst;
clk_odd;
output[3:0]
count;
reg
clk_odd;
reg[3:0]
count;
parameter
N = 6;
always @ (posedge clk)
if(! rst)
begin
count <= 1'b0;
clk_odd <= 1'b0;
end
else
if ( count < N/2-1)
begin
count <= count + 1'b1;
end
else
begin
count <= 1'b0;
clk_odd <= ~clk_odd;
end
endmodule
奇数倍分频:归类为一般的方法为:对于实现占空比为 50%的 N 倍奇数分频,首先进
行上升沿触发进行模 N 计数,计数从零开始,到(N-1)/2 进行输出时钟翻转,然后经过
(N-1)/2 再次进行翻转得到一个占空比非 50%奇数 n 分频时钟。再者同时进行下降沿触发
的模 N 计数,到和上升沿过(N-1)/2 时,输出时钟再次翻转生成占空比非 50%的奇数 n 分
频时钟。两个占空比非 50%的 n 分频时钟相或运算,得到占空比为 50%的奇数 n 分频时钟。
module even_division(clk,rst,count1,count2,clk_even);
input
clk,rst;
output[3:0]
count1,count2;
output
clk_even;
reg[3:0]
count1,count2;
reg
wire
clkA,clkB;
clk_even;
parameter
N = 5;
assign clk_re
= ~clk;
assign clk_even = clkA | clkB;
always @(posedge clk)
if(! rst)
begin
count1 <= 1'b0;
clkA
<= 1'b0;
end
else
if(count1 < (N - 1))
begin
count1 <= count1 + 1'b1;
if(count1 == (N - 1)/2)
begin
clkA <= ~clkA;
end
end
else
begin
clkA <= ~clkA;
count1 <= 1'b0;
end
always @ (posedge clk_re)
if(! rst)
begin
count2 <= 1'b0;
clkB
<= 1'b0;
end
else
if(count2 < (N - 1))
begin
count2 <= count2 + 1'b1;
if(count2 == (N - 1)/2)
begin
clkB <= ~clkB;
end
end
else
begin
clkB <= ~clkB;
count2 <= 1'b0;
end
endmodule
任意整数带小数分频的设计
任意整数带小数分频的基本原理是:
采用脉冲吞吐计数器和锁相环技术先设计两个不同分频比的整数分频器。
然后通过控制单位时间内两种分频比出现的不同次数来获得所需要的小数分频值。
若设计一个分频系数为 10.1 的分频器,即可以将分频器设计成 9 次 10 分频和 1 次 11 分频,这样,总的
分频值为:
F=(9×10+1×11)/(9+1)=10.1
从这种实现方法的特点可以看出,由于分频器的分频值不断改变,分频后得到的信号抖动一般较大。
当分频系数为 N-0.5(N 为整数)时,可控制扣除脉冲的时间,以使输出成为一个稳定的脉冲频率,而不是一
次 N 分频,一次 N-1 分频。
一般而言,这种分频由于分频输出的时钟脉冲抖动很大,故在设计中的使用已经非常少。但是,这也是可
以实现的。
上面都是用计数器实现的分频,除此之外,还可以用状态机来实现。
下面给出一个任意整数分频器的代码:
module divn
(
input clk,
input
rst_n,
output o_clk
);
parameter WIDTH = 3;
parameter N
= 6;
reg [WIDTH-1:0] cnt_p;
reg [WIDTH-1:0] cnt_n;
reg
reg
assign o_clk = (N == 1) ? clk :
clk_p;
clk_n;
(N[0]) ? (clk_p | clk_n) : (clk_p);
always@(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt_p <= 0;
else if (cnt_p == (N-1))
cnt_p <= 0;
else
cnt_p <= cnt_p + 1;
end
always@(posedge clk or negedge rst_n) begin
if (!rst_n)
clk_p <= 1;
else if (cnt_p < (N>>1))
clk_p = 1;
else
clk_p = 0;
end
always@(negedge clk or negedge rst_n) begin
if (!rst_n)
cnt_n <= 0;
else if (cnt_n == (N-1))
cnt_n <= 0;
else
cnt_n <= cnt_n + 1;
end
always@(negedge clk or negedge rst_n) begin
if (!rst_n)
clk_n <= 1;
else if (cnt_n < (N>>1))
clk_n = 1;
else
clk_n = 0;
end
endmodule