任意分数 Verilog 实现
网上常见的多为小数分频,分数分频也为有规律的分频,如 N/2、
M-1/N 等。而像 M/N 型分数分频却很少。现介绍一下本人的分数分频实现方法,
如果不当之处敬请指教。
分数分频实现基本上都是靠吞脉冲方法实现,如 5/2 分频,就可
以分成一个 2 分频,一个 3 分频接替出现,这样(2+3)/2 就是 5/2 分频。
下面以 68/9 为例介绍下怎么计算。
68=9*7+5,即商为 7,余数为 5。可以推出 68/9 分频,可以看成
5 个 8 分频和 4 个 7 分频,即(5*8+4*7)/9=68/9。这个 7 分频和 8 分频中的数
字 7 和 8 就是从商中得出来的。那 5 个 8 分频和 4 个 7 分频中的数字 5 和 4 就是
从余数中的出来的,5 是余数,4 是(9-5)。
分 子 : numerator 。 分 母 denominator 。 商 quotient 。 余 数
remainder。(翻译不是很准确,表达下意思就行了,呵呵)。
numerator=quotient*denominator+remainder.那么 numerator/
denominator 分频就可以通过 remainder 个(quotient+1)分频和(denominator
-remainder)个 quotient 分频组成。
还是以 68/9 为例。我们得出了 5 个 8 分频和 4 个 7 分频可以实现
这个分数分频,但这 5 个 8 分频和 4 个 7 分频怎么放置呢?
先放 5 个 8 分频,再放 4 个 7 分频,这样绝对是不行的。为了均
匀的放置这两种频率,我从小数分频中学到一种方法。找个临时变量 temp(程
序中用的是 sum)。初始化为 0。每次分频完让它加上余数,判断是否大于分母,
如果小于分母,择输出 7 分频,否则输出 8 分频,并且将这个值减去分母(让它
小于分母)。这样 temp 值就变成了 5 1 6 2 7 3 8 4 0 5……
分频值就成了 7 8 7 8 7 8 7 8 8 7 8 7 8 7 8 7 8 8……可以统计一下 7 分频
和 8 分频的比例就正好是 4:5,这样就实现了分数分频。
程序如下所示:
输入信号:clk,rst,clkin(要分频的时钟信号),numerator(分子), denominator,
(分母)
输出信号:pulse
中间信号:quotient(商),remainder(余数)等
hightime 为输出信号 pulse 输出高电平时间,可控制占空比
/*************************************************
//module name:fredivAB
//designer:kang
//date:2010-10-08
//version:1.00
*************************************************/
module fredivAB(
//input signals
clk,
rst,
clkin,
numerator,
//fenzi
denominator,
//fenmu
//output signals
pulse
);
input clk;
input rst;
input clkin;
input [15:0] numerator;
input [15:0] denominator;
output pulse;
reg pulse;
//parameter HIGHTIME=16'd2;
wire [15:0] quotient;
//shang
wire [15:0] remainder;
//yushu
reg ina;
reg inb;
reg upclk;
reg counter_clkin;
reg [15:0] counter;
reg [15:0] divnum;
reg [15:0] sum;
reg flag;
reg [15:0] counter_pulseh;
wire [15:0] hightime;
assign quotient=(denominator)?numerator/denominator:16'h0;
assign remainder=(denominator)?numerator%denominator:16'h0;
assign hightime={1'b0,quotient[15:1]};
//assign hightime=16'h1;
//save the prior and current state of clkin
always @(posedge clk or negedge rst)
begin
if(!rst)
else
end
begin
ina<=0;
inb<=0;
end
begin
ina<=clkin;
inb<=ina;
end
//check posedge pf clkin
always @(posedge clk or negedge rst)
begin
if(!rst) upclk<=0;
else if(!inb&ina) upclk<=1'b1;
else upclk<=0;
end
//fre div counter
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
counter<=0;
end
else if(counter==divnum) counter<=16'h0;
else if(upclk) counter<=counter+1'b1;
else counter<=counter;
end
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
sum<=0;
flag<=0;
end
else if(counter==divnum)
begin
if((sum+remainder)>=denominator)
//fenmu
begin
sum<=sum+remainder-denominator;
flag<=1;
end
begin
else
sum<=sum+remainder;
flag<=0;
end
end
end
always @(posedge clk or negedge rst)
if(!rst) divnum<=0;
else if(flag) divnum<=quotient+1'b1;
else divnum<=quotient;
//counter_plush
always @(posedge clk or negedge rst)
begin
if(!rst) counter_pulseh<=hightime+16'h1;
else if((counter==divnum)&&divnum) counter_pulseh<=0;
else if(upclk) counter_pulseh<=counter_pulseh+1'b1;
end
//pulse produce
always @(posedge clk or negedge rst)
if(!rst) pulse<=1'b0;
else if(counter_pulseh<=(hightime-1)) pulse<=1'b1;
else pulse<=1'b0;
endmodule
在此附上仿真波形