嵌入式之串口通信
串口数据溢出
事起缘由
串口单线通信,遇到一开串口,程序就“卡死”的情况,分析了原因,故有此文。
现象
程序在不断进串口中断函数,造成其他程序无法正常执行。
如果有串口溢出,可以在串口接收中断位置打断点,很容易触发该现象。
分析原因
硬件与配置
出现该现象时先是分析了硬件原因与配置原因:
- 是否波特率相同
- 115200波特率的由来:
最初是由 11.0592MHz 的晶振 通过6分频, 然后在16分频后,得到的。
- 115200波特率每秒可传输多少个字节?
如果设置波特率为115200,设置通信帧为1bit起始位+8bit数据帧+无校验+1bit停止位(传输1个char 需要10bit),那么每秒钟最多可以传输115200bit/10bit = 11520个字节(1个字节大约86.8us;实际使用时由于存在干扰及其他原因,可能要打个8折)。
- 是否频率相同
- 两边设置的波特率都为115200,但是波特率是怎么计算呢?
在计算前需先明白什么是过采样:以GD32F330R8为例,串口接收器支持x16(默认)过采样和x8过采样,x16过采样即发送方发送数据后,串口接受器会将每个bit采样16次(对一个信号进行16分频采样, 即将信号分成16等分后进行采样,一般取中间的采样值),如果是x8过采样,则采用8次。
baud= uclk / usartdiv 即: 波特率 = 所选串口所在时钟总线的频率 / 波特率分频系数
baud:常见有 9600、19200、115200
uclk:根据不同芯片、不同主频、不同总线来选择,不过常配置为36MHz、54MHz、72MHz
usartdiv:不同过采样率计算方式不同;一般来讲:
x16过采样率计算方式为:usartdiv = uclk / (16 * baud) ;大多芯片默认为x16采样,也可自己配置,寄存器 USART_CTL0中的OVSMOD位,OVSMOD = 0 为x16,OVSMOD = 1 为x8
x8过采样率计算方式为:usartdiv = uclk / (8 * baud)
- 时钟误差
采样数据的误差:在最后一个Bit位采样时,允许极限偏移为50%,假如用1个起始位+9个数据位+1个奇偶;校验位+1个停止位来计算,那么每位偏差最高为:±50% / 12 = ±4.16%
因此,对于串口通信来说,可以粗略认为,当时钟误差小于±2%时,通信是比较可靠的。
对于客户实际的应用系统,考虑到UART是一个异步通讯,通讯的稳定性取决于双方的时钟精度,不是说只有一方的精度满足要求,系统就能正常工作,所以需要全局考虑。
软件逻辑
将所有代码逐步屏蔽,最后定位到串口上。
网上查资料,查芯片用户手册,逐步定位到串口溢出(又称过载 - Overrun)上。以GD32F330为例,串口的溢出标志位(ORERR)位于USART_STAT寄存器中
以下是本次经验与教训:
串口溢出发生一般可能有以下几种情况:
数据在接收缓冲区中未被及时读取。
串口接收中断被更高优先级的中断打断,且打断时间比较长。
擦写单片机内部flash时,耗时较长,导致串口中断无法响应。
解决办法
提高中断优先级。
判断并清除溢出中断标志(ORERR) - 只需读取一下串口数据寄存器(USART_RDATA)即可。
关闭溢出检测功能(不推荐,此操作虽然可以解决”卡死”现象,但可能会使上个数据被覆盖,导致数据丢失)。
建议
中断程序(不仅仅是串口中断)要响应所有中断,不要只响应接收中断,其他错误中断也要处理,否则会频繁进入中断造成“卡死”。 2 STM32串口只有一个硬件BUF,个人认为是硬伤。115200波特率的情况下,大家算下一个字节是多少us? 只要串口中断被卡主住这么长时间不处理,就造成溢出。 3 把中断优先级提高、用DMA、人工优化。
尽量及时读取串口接收寄存器中的数据
补充
RC振荡器
RC振荡器中的“RC”代表电阻(Resistor)和电容(Capacitor)。
RC振荡器是一种利用电阻和电容元件构成的振荡器,通过这些元件的组合来产生振荡信号。
RC振荡器的基本工作原理
RC振荡器的工作原理基于RC网络提供的相移。RC网络在电路中产生相位差,通常需要至少两个单极RC网络来获得180度的相移,从而产生振荡。在实际应用中,由于每个RC级很难精确获得90度的相移,因此通常使用多个RC级级联来达到所需的相移。通过调整电阻和电容的值,可以在特定频率下实现稳定的振荡。
RC振荡器的类型和应用
RC振荡器有多种类型,包括桥式振荡电路和双T式振荡电路等。桥式振荡电路是最常用的类型之一,它利用RC串并联选频网络来实现振荡。这些不同类型的RC振荡器在电子设备中有广泛的应用,例如在无线电、通信系统、时钟电路等中。