设驱动时钟频率为Fc,相位增量为M,寄存器计数值上限为uplimit,输出频率为Fo,则Fo=Fc*M/uplimit;
在进行verilog编程时,以下UP=uplimit
always@(posedge Fc)
if(nco >= UP) begin
nco <= nco - UP;
pulse <= 1;
end
else begin
pulse <= 0;
nco <= nco + M;
end
end
经仿真可以发现,这个pulse的频率并不是Fo=Fc*M/UP,而是Fc*M/(UP+M)
这是为什么呢?
我们用一个简单的例子进行一下做一个假设,以便清楚的说明问题:
设Fc=16MHz,M=2,uplimit=8,则输出Fo=16*2/8=4MHz
但按以上程序实现时,nco初始值为UP,则判断 if(nco >= UP) 成立,执行nco <= nco - UP; 后nco变为0 ,以下列出了8个时钟的nco值:
第n个时钟 1 2 3 4 5 6 7 8……
nco的值 0 2 4 6 8 0 2 4……
由此可见,nco的值是0-2-4-6-8-0-2-4-6-8……周期为5个值的循环,而我们期待的是4个值的循环,问题出现在nco的循环初值和终值的选取上,初值和终值的选取应保证nco的循环周期是4个值即可……
因此可以将UP设为uplimit-M,或者将初值设为 nco <= nco - UP+M就可以了……
也许会有朋友问为什么nco到达上限后不将其设为0(或者M),而是设为nco-UP(或者nco-UP+M),这是因为并不是每一个我们需要产生的Fo的频率都是Fc的整数分之一,当Fo不是Fc的整数分之一时,如果到上限后清零nco的话会产生一个固定的频率偏差,而如程序中所设则可以使用pulse的输出频率从平均的意义上来讲是所需的Fo,例如:
当up=7时,所产生的频率为Fo=16*2/7=32*7=4.57
按程序中所设(此处将UP按上所阐述设为limit-M=5):
第n个时钟 1 2 3 4 5 6 7 8 9 10 11 12……
nco的值 0 2 4 6 1 3 5 0 2 4 6 1……
即一次是0-2-4-6的四值循环,一次是1-3-5的三值循环,四值循环的输出频率为Fo=Fc/4=4MHz 和Fo=Fc/3=16/3=5.33,平均频率为Fo=Fc/(3+4)/2=4.57……
注意:这里计算平均频率不能简单的将两个输出频率相加除2……
但是,若if(nco >= UP) 成立后直接将nco置0,则nco的循环将一直是0-2-4-6的四值循环,输出频率也将一直是4Mhz,并非是需要的4.57Mhz了……