UART通信的误差计算:
接收方与发送方频率不准,可能引起累积误差?
晶振时间积累误差
比如发送器和接收器,两边的晶振,发生了最大的相反方向的漂移,内置8MHz晶振误差精度0.5% ,两边累积最大误差达到1%
内置8MHz晶振,实际则为 8 MHz*(+ -1.005) = 7.96MHz~ 8.04MHz 接收方和发送方,晶振都不准,这将对通信产生不确定影响。
下图是两个晶振的误差对比
晶振 | 频率精度 | 60s误差 | ms误差 | us误差 | 通信误差 通信速度230400bit/s |
内部8Mhz | +-5000ppm (0.5%) | 60s ±0.3s | 1000ms ±5ms | 1 000 000 us ± 5000us | 4.34us ±0.0217us |
外部8MHz | +-30ppm (0.003%) | 60s ± 0.0018s | 1 000 000 us ± 30us |
从上面表格可以看出晶振误差对单片机系统时间的影响。
假设,通信速度230400bit/s , 则发送1bit数据的时间 = 1000000us / 230400bit = 4.34±0.0217us
每发1bit 数据时间消耗为 4.34±0.0217us 误差为±0.5%
可以想象,如果连续发100个bit,误差时间会积累到2.17us!当误差积累到1/2bit的时候,接收器的这个位就错开了。 导致数据偏移 ,发生错误。
不过,我们的UART有开始位,停止位,每10bit数据发完,都会重新从开始位、停止位、来重新检测边沿信号。再确定开始点。
因此这部分的积累误差,没有影响!因为UART的数据帧最多也就是10bit左右
晶振不准导致配置出来产生误差?
如果你知道真实频率就不会,因为可以调节分频值,最后达到标准频率
但,如果你不知道晶振发生了漂移,想当然,仍然使用标准频率进行计算,那就会有较大误差。
我们用最坏的情况做一个假设
在这个设置下 230400bps 8n1
不准的两个晶振( 8MHz ±1% ):
->内置7.92MHz不准晶振的发送设备1
->内置8.08MHz不准晶振的接收设备2
导致不准的外设频率:
发送设备1的外设频率 PCLK1 = PLL1 = (IRC7.92M/2) * 4 = 15.84 MHz
接收设备2的外设频率 PCLK2 = PLL2 = (IRC8.08M/2) * 4 = 16.16 MHz
最多分配频率 : 每1bit数据,能分配的频率数 ( PCLK / 波特率):
发送设备1 每1bit数据最多分配的时钟个数 = 15,840,000 / 230400 = 68.75 Hz/bit
接收设备2 每1bit数据最多分配的时钟个数 = 16,160,000 / 230400 = 70.14 Hz/bit
过采样设置:
由于过采样技术要求,1bit数据最少分配x8个采样时钟!默认一般是x16个采样时钟!
所以上面我们给每bit分配的频率,还要再除上16或者8
除出来这个数(也就是USARTDIV)>1 ,时钟才能完全撑得起这个采样率。
(否则,时钟频率都没那么快,1bit数据怎么采样16次?)
过采样数,也就是手册中常看到的。过采样倍率 = (8*(2-OVER8))
OVER8寄存器的值 =0表示 x16采样,
OVER8寄存器的值 =1表示 x8采样
对于GD32这种,带入进去算出来,就是x8或者x16倍过采样。
计算期望中的分频系数:
此时熟悉的公式就出来了:USARTDIV = PCLK1 / (波特率*(8*(2-OVER8)) )
正常PCLK= 36.00 MHz设备 USARTDIV = 36,000,000 / ( 230400 *16 ) = 9.765625 (100%)
正常PCLK= 16.00 MHz设备 USARTDIV = 16,000,000 / ( 230400 *16 ) = 4.340278 (100%)
晶振发生偏移的 发送设备1 USARTDIV1 = 15,840,000 / ( 230400 *16 ) = 4.297 (98.9999%)
晶振发生偏移的 接收设备2 USARTDIV2 = 16,160,000 / ( 230400 *16 ) = 4.384 (101.00159%)
只要USARTDIV >1,则表明MCU的运行频率,可以撑得起来这个采样率。
根据期望的分频系数,再设置USART_BAUD 寄存器 :
根据上面算出的带小数点的分频系数 USARTDIV,需把整数部分和小数部分分开。
小数部分*16,然后四舍五入,取整填入到小数部分的位中。如果这个值超过16要进位到整数部分。
而整数部分,则直接转换成16进制。最后将两部分用 " | "拼起来,就是USART_BAUD 寄存器的值了。
下面是实际的转换过程:
比如:
正常PCLK= 36.00 MHz 的设备算出 USARTDIV = 9.765625 四舍五入下 9.77
然后把9 和 0.77分别处理。9就是0x9, 0.77先要乘以16 =12.32 取整数=12 ,那么12就是0xC
所以配置寄存器USART_BAUD = 0x9| 0xC =0x9C
同理:
正常PCLK= 16.00 MHz设备 USARTDIV = 4.340 ≈ 4.30
配置寄存器USART_BAUD = 0x4 | 0x5 (0.34*16 = 5.44 ≈ 5 ) = 0x45
晶振发生偏移的 发送设备1 USARTDIV1 = 4.297 ≈ 4.30
寄存器配置USART_BAUD = 0x4 | 0x5 (0.30*16 = 4.8 ≈ 5 ) = 0x45
晶振发生偏移的 接收设备2 USARTDIV2 = 4.384 ≈ 4.38
寄存器配置USART_BAUD = 0x4 | 0x6 (0.38*16 = 6.08 ≈ 6 ) = 0x46
根据实际的寄存器设置,这里反算出了,实际中的分频系数
正常PCLK= 36.00 MHz设备 实际USARTDIV = 9 + ( 12/ 16) = 9.75
正常PCLK= 16.00 MHz设备 实际USARTDIV = 4 + ( 5/ 16 ) = 4.3125
发送设备1 实际USARTDIV1 = 4 + ( 5/ 16 ) = 4.3125
接收设备2 实际USARTDIV2 = 4 + ( 6 /16 ) = 4.375
由于:USARTDIV = PCLK / ( 实际波特率*16)
则:实际波特率 = PCLK /( USARTDIV *16)
这样就算出了实际的波特率了。 这样对比标准的波特率,就知道误差了。
编写了一个计算器,有兴趣的朋友可以试试。
PCLK Hz | PCLK MHz | 过采样 | 标准波特率 | 波特率误差 | 实际波特率 | 期望分频系数 | 实际分频系数 |
15840000 | 15.84 | 16 | 230400 | -0.36% | 229565 | 4.297 | 4.3125 |
16160000 | 16.16 | 16 | 230400 | 0.20% | 230857 | 4.384 | 4.375 |
16000000 | 16 | 16 | 115200 | -0.08% | 115108 | 8.681 | 8.6875 |
16000000 | 16 | 16 | 230400 | 0.64% | 231884 | 4.340 | 4.3125 |
16000000 | 16 | 16 | 460800 | -0.79% | 457143 | 2.170 | 2.1875 |
16000000 | 16 | 16 | 921600 | 2.12% | 941176 | 1.085 | 1.0625 |
36000000 | 36 | 16 | 230400 | 0.16% | 230769 | 9.766 | 9.75 |
72000000 | 72 | 16 | 921600 | 0.16% | 923077 | 4.883 | 4.875 |
72000000 | 72 | 16 | 115200 | 0.00% | 115200 | 39.063 | 39.0625 |
72000000 | 72 | 16 | 2250000 | 0.00% | 2250000 | 2.000 | 2 |
72000000 | 72 | 16 | 230400 | 0.16% | 230769 | 19.531 | 19.5 |
72000000 | 72 | 16 | 115200 | 0.00% | 115200 | 39.063 | 39.0625 |
8000000 | 8 | 16 | 230400 | -0.79% | 228571 | 2.170 | 2.1875 |
4000000 | 4 | 16 | 115200 | -0.79% | 114286 | 2.170 | 2.1875 |
16MHz的外设频率 ,设置成921600bps 误差2.12%,有点大,但我赌它能勉强通信。
总误差在<2.5% 都可以通讯,但可靠的角度来看误差<1%,甚至更小才好!
这个下面的表,是从官方手册里面截的, 和我上面Excel表格里计算出来的一致。
波特率 | PCLK 36MHz | PCLK 72MHz | |||||
序号 | 标准波特率 Kbps | 实际波特率 | 实际分频系数USARTDIV | 误差% | 实际波特率 | 实际分频系数USARTDIV | 误差% |
1 | 2.4 | 2.400 | 937.5 | 0% | 2.4 | 1875 | 0% |
2 | 9.6 | 9.600 | 234.375 | 0% | 9.6 | 468.75 | 0% |
3 | 19.2 | 19.2 | 117.1875 | 0% | 19.2 | 234.375 | 0% |
4 | 57.6 | 57.6 | 39.0625 | 0% | 57.6 | 78.125 | 0% |
5 | 115.2 | 115.384 | 19.5 | 0.15% | 115.2 | 39.0625 | 0% |
6 | 230.4 | 230.769 | 9.75 | 0.16% | 230.769 | 19.5 | 0.16% |
7 | 460.8 | 461.538 | 4.875 | 0.16% | 461.538 | 9.75 | 0.16% |
8 | 921.6 | 923.076 | 2.4375 | 0.16% | 923.076 | 4.875 | 0.16% |
9 | 2250 | 2250 | 1 | 0% | 2250 | 2 | 0% |
10 | 4500 | 不可能 | 不可能 | 不可能 | 4500 | 1 | 0% |
如果晶振频率偏移了1%,并且我们不知道它偏移了,仍然设置正常晶振的值会怎样?
回到最初的问题,以上都是基于,我们知道晶振的具体频率才能准确设置分频的。
但,如果我们误以为晶振是16MHz但它实际上是15.84MHz,或者16.16MHz,它会增加多少差多少呢?
PCLK Hz | PCLK MHz | 过采样 | 标准波特率 | 波特率误差 | 实际波特率 | 期望分频系数 | 实际分频系数 |
15840000 | 15.84 | 16 | 230400 | -0.36% | 229565 | 4.297 | 4.3125(误以为PCLK =16MHz 所以设置这个值) |
16160000 | 16.16 | 16 | 230400 | 1.65% | 234203 | 4.384 | 4.3125(误以为PCLK =16MHz 所以设置这个值) |
16000000 | 16 | 16 | 230400 | 0.64% | 231884 | 4.340 | 4.3125 |
看到上表中,误差明显增大了, 1.65 % + 0.36% = 2.01% 总偏差 > 2%了。
所以如果晶振发生了漂移,对通信是有影响的。收发两边的晶振如果频率相差>2%,那就要考虑晶振引起的通信误差问题了。
如果是±0.5%以内的误差是可以接受的, 如果使用稳定的外部晶振,那晶振的误差仅为±0.003%,则无需担心晶振引起的误差。