路由器,我们在日常生活、工作中都经常用到,但不知道大家对“波特率发生器”是否知道呢?本文收集整理了一些资料,希望本文能对各位读者有比较大的参考价值。
波特率发生器
所谓波特率发生器就是从输入时钟转换出需要的波特率clk。
波特率发生器不是产生波特率时钟的,波特率时钟频率/波特率因子=波特率。
FPGA波特率发生器
这里我们使用串行连接的最大速度115200波特,其他较慢的波特也很容易由此产生。
FPGA通常运行在远高于115200Hz的时钟频率上(对于今天的标准的来说RS-232真是太慢了),这就意味着我们需要用一个较高的时钟来分频产生尽量接近于115200Hz的时钟信号。
从1.8432MHz的时钟产生
通常RS-232芯片使用1.8432MHz的时钟,以为这个时钟很容易产生标准的波特率,所以我们假设已经拥有了一个这样的时钟源。
只需要将 1.8432MHz 16分频便可得到 115200Hz的时钟,多方便啊!
reg [3:0] BaudDivCnt;
always @(posedge clk) BaudDivCnt <= BaudDivCnt + 1;
wire BaudTick = (BaudDivCnt==15);
所以 "BaudTick" 每16个时钟周期需要置位一次,从而从1.8432MHz的时钟得到115200Hz的时钟。
从任意频率产生
早期的发生器假设使用1.8432MHz的时钟。但如果我们使用2MHz的时钟怎么办呢?要从2MHz的时钟得到 115200Hz,需要将时钟 "17.361111111..." 分频,并不是一个整数。我的解决办法是有时候17分频,有时候18分频,使得整体的分频比保持在 "17.361111111"。这是很容易做到的。
下面是实现这个想法的C语言代码:
while(1) // 死循环
{
acc += 115200;
if(acc >=2000000) printf("*"); else printf(" ");
acc %= 2000000;
}
这段代码会精确的以平均每 "17.361111111..." 个时钟间隔打印出一个"*"。
为了从FPGA得到同样的效果,考虑到串行接口可以容忍一定的波特率误差,所以即使我们使用17.3或者17.4这样的分频比也是没有关系的。
FPGA波特率发生器
我们希望2000000是2的整数幂,但很可惜,它不是。所以我们改变分频比,"2000000/115200" 约等于 "1024/59" = 17.356. 这跟我们要求的分频比很接近,并且使得在FPGA上实现起来相当有效。
//10 位的累加器 ([9:0]), 1位进位输出 ([10])
reg [10:0] acc; //一共11位!
always @(posedge clk)
acc <= acc[9:0] + 59; //我们使用上一次结果的低10位,但是保留11位结果
wire BaudTick = acc[10]; //第11位作为进位输出
使用 2MHz 时钟, "BaudTick" 为 115234 波特, 跟理想的115200波特存在 0.03% 的误差。
参数化的FPGA波特率发生器
前面的设计我们使用的是10位的累加器,如果时钟频率提高的话,需要更多的位数。
下面是一个使用 25MHz 时钟和 16 位累加器的设计,该设计是参数化的,所以很容易根据具体情况修改。
parameter ClkFrequency = 25000000; // 25MHz
parameter Baud = 115200;
parameter BaudGeneratorAccWidth = 16;
parameter BaudGeneratorInc = (Baud<<BaudGeneratorAccWidth)/ClkFrequency;
reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc;
always @(posedge clk)
BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc;
wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth];
上面的设计中存在一个错误: "BaudGeneratorInc"的计算是错误的, 因为 Verilog 使用 32 位的默认结果, 但实际计算过程中的某些数据超过了32位,所以改变一种计算方法。
波特率发生器
parameter BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4);
这行程序也使得结果成为整数,从而避免截断。
这就是整个的设计方法了。现在我们已经得到了足够精确的波特率,可以继续设计串行接收和发送模块了。
经改造的DDS功能用作波特率发生器
一般情况下,可以用一个现有的振荡器,为一个UART产生一个波特率时钟。振荡器频率必须作分频,而分频会带来波特率误差。表1表示当用一个8 MHz晶振和一个普通的二进制分频器生成波特率时,产生误差的百分比。本例中的系统可以获得一个比波特率快16倍的时钟。
当示波器频率不相匹配时,波特率设置中的误差会增加。此时,可以增加一个工作在18.432 MHz的振荡器,以尽可能减小误差率。另外,可以采用DDS(直接数字综合)方法,以较高波特率使用相同振荡器,从而降低误差。
综上所述,本文已为讲解FPGA波特率发生器、经改造的DDS功能用作波特率发生器等等,相信大家对波特率发生器的认识越来越深入,希望本文能对各位读者有比较大的参考价值。
浏览过本文<波特率发生器>文的人也浏览了
串口波特率
http://baike.cntronics.com/abc/2424
波特率是什么?
http://baike.cntronics.com/abc/2391
基于单片机串行口红外通信的设计
http://club.cntronics.com/space.php?uid=198349&do=blog&id=32318