GD32F4(10):GD32转RS422在115200下接收乱码分析

GD32F450:串口转RS485在115200下接收乱码


抛出我遇到的问题:使用gd32f450,使用串口转rs485通信,在9600下正常通信,在115200下数据出现乱码。

如果你的串口是用来转RS422、RS485、RS232等其它协议,那么你可要好好看一下这篇文章,因为GD32的芯片可能不是一个好的选择,它的兼容能力太差了

如果你只是uart串口间来回传输数据,就出现了乱码,那么乱码大概的时钟没配置对,请看我这两篇文章:
GD32F4(5):GD32F450时钟配置为200M过程分析
GD32F4(6):晶振引发串口乱码

本文讲述的乱码不是程序的原因,而是使用了转换芯片(如uart转RS422、485、232)导致的电平时间长度发生改变引发的乱码
在这里插入图片描述

先说结论:由于不同mcu的串口ip核设计的原理不同,导致性能也各有差异,而gd32的串口设计方案容错能力太差,主要串口波形稍微不标准,就会导致读取失败,引发乱码。这种由于IP核设计导致的问题,几乎没有可修复的可能。

1. 知识储备

首先我们要知道,在定义UART协议的时候,我们都是以bit为单位的,比如起始位是一个bit的低电平,数据一位占据的是1个bit低或1个bit的高,停止位是1或1.5或2个bit。这里其实隐含了一个事情,那就是按理说每一个状态都是有时间规定的,即倍数于一个bit的时间,而bit的时间和波特率是一一对应的。

举个简单的例子:

  • 当波特率为9600的时候,每一个bit的时间为1s/9600 = 104us,也就是说起始位应该是104us的低电平,一个0应该是104us的低电平,一个1应该是104us的高电平。

  • 当波特率为115200的时候,每一个bit的时间为1s/115200 = 8.68us,也就是说起始位应该是8.68us的低电平,一个0应该是8.68us的低电平,一个1应该是8.68us的高电平。

可是对于通信来讲,我们都知道数据传输的时候0和1的表示时间难免和bit时间有一些误差,可能0的时间稍短些,1的时间电平稍长些,这些都是很正常的事情,只要在一个合理的范围内,应该都能识别,可是GD32对于这种兼容效果极差,就是这件事,直接导致了stm32换型GD32失败。

下面是我的遭遇

2. 环境

我为GD32F450设计了一个UART转RS422,转换模块型号为CA-IS3086W,下面是它的设计图(声明:我的问题不是由于这个电路引发的,这里只是给个例子,这个CA-IS3086W很好用):
在这里插入图片描述

当我把GD32程序写完,用usb转RS422模块来进行测试,我用的是下面这个模块(这个模块就是坑的开始,我后面说):
在这里插入图片描述

这个是同时支持422和485的模块,我把这个蓝色外壳打开,这个芯片422是通过两个串口转485来实现的。

3. 操作

我用串口助手发送数据,通过usb转422发送给PCB板,PCB板有RS422转uart模块,uart连接mcu;

当我发送的波特率为9600的时候,mcu可以正常接收到数据。

当我发送的波特率为115200的时候,mcu接收到数据会存在部分乱码,因为9600数据是正常的,所以首先排除了时钟的问题,于是我就发送0x55或0xaa,然后用示波器来看波形,如下:
在这里插入图片描述

要排除问题,于是我将电路图从UART处断开,在用USB转串口,分别接到两头,发现GD32可以正常和USB转串口收发数据,422侧也可以正常和USB转串口收发数据。所以我就怀疑可能是UART线阻抗不匹配的问题,于是我就把USB转串口的RX引脚直接焊接到了MCU的RX引脚,这样当422收到数据的时候,mcu和USB转串口应该收到一样的数据,结果是USB转串口正常收到数据,mcu收到的是乱码。我蒙了

在GD32串口RX引脚处看到波形如上图,没有任何问题,上升沿和下降沿都很陡峭,也没有干扰的存在,那为什么呢,下面是我对串口采集数据的详细分析。

4. 插入一个知识点:不同MCU串口ip核实现原理

我们其实都知道,在配置mcu的UART的时候,其实有一个配置叫过采样(我们一般都是默认值,不配置),一般可以配置成8倍或16倍,过采样其实就是判断是高还是低的连续采样次数,我们以过采样为8来采集一次低电平为例,如下:
在这里插入图片描述

而当我们的波形不规整的时候,就会出现下面的情况:
在这里插入图片描述

因此怎样通过对采样的判断来确定bit的值就成了重中之重,下面我们就讨论一下各家的实现方法。

4.1 首先我们来看一下STM32f的串口是怎样识别数据的

声明:下面这部分来自stm32f7芯片手册

stm32对串口的数据识别主要包含两部分,起始位的识别数据位的识别

起始位识别

不管是16 倍还是 8 倍过采样,起始位检测序列相同。都是按照16倍的方式判断,就是起始位不受16 倍或 8 倍过采样配置的影响,在 USART 中,识别出特定序列的采样时会检测起始位。此序列如下:

1 1 1 0 X 0 X 0 X 0 0 0 0

起始位识别图,如下:

在这里插入图片描述

  1. 如果下降沿序列不完整,起始位检测将中止,接收器将返回空闲状态(无标志位置 1)等待下降沿。

  2. 如果 3 个采样位均为 0(针对第 3 位、第 5 位和第 7 位进行首次采样时检测到这 3 位均为 0;针对第 8 位、第 9 位和第 10 位进行第二次采样时检测到这 3 位均为 0),可确认起始位(RXNE 标志位置 1,RXNEIE=1 时生成中断)。

  3. 如果满足以下任意条件时,可验证起始位(RXNE 标志位置 1,如果 RXNEIE=1 则生成中断),但同时 NF噪声标志位也会置 1:
    a. 对于两次采样,有 2 位为 0(针对第 3 位、第 5 位和第 7 位进行采样;针对第 8 位、第 9 位和第 10 位采样)。
    b. 如果其中一次采样时(对第 3 位、第 5 位和第 7 位进行采样或对第 8 位、第 9 位和第 10位进行采样),3 个采样位中有 2 个为0。

    如果条件 a 或条件 b 都不满足,则启动检测中止,接收器返回空闲状态(无标志位置 1)。

当起始位满足要求,那么就进入数据位检测

数据检测的时候,过采样16和过采样8是不同的,具体如下:

过采样16
在这里插入图片描述

过采样8
在这里插入图片描述

其实过程都一样,就是通过采集中间的3次来判断这个bit的高低,下面的对照表:
在这里插入图片描述

但是要注意,当串口的电平延时不标准的时候(比如低电平时间短),会导致采集的这三次不在bit的中间,这就是容错性的问题关键了。

4.2 GD32F4串口识别

声明:下面这部分来自GD32F450芯片手册

起始位识别

用户手册只写了数据的读取方法,起始位的判断方法还不敢确定,因此我就在网上找到了这样的一篇文章《GD32F450的USART接收数据错误问题》博主问FAE可知道,GD32的uart的IP核是GD自己自行设计的,说是连续采集16个点全为0,作为起始位,如果是这样,那这也太坑了,这样非常容易误判。

数据位检测

数据位的识别数据手册写的很清楚,数据手册说数据的检测有两种配置,通过USART_CTL2中位OSB来配置。

当OSB=0(默认):那么接收器通过获取三个采样点的值来估计该位的值。这种状态下又分为8倍过采样和16倍过采样。如果是8倍过采样模式,选择第3、4、5个采样点;如果是16倍过采样模式,选择第7、8、9个采样点。如果在3个采样点中有2个或3个为0,该数据位被视为0,否则为1。如果3个采样点中有一个采样点的值与其他两个不同,不管是起始位,数据位,奇偶校验位或者停止位,都将产生噪声错误(NERR)。如果使能DMA,并置位USART_CTL2寄存器中ERRIE,将会产生中断。

下面是过采样方式接收一个数据位(OSB=0):
在这里插入图片描述

当OSB=1:接收器将仅获取一个采样点来估计一个数据位的值。在这种情况下将不会检测到噪声错误。也就是如果是8倍过采样模式,选择第4个采样点;如果是16倍过采样模式,选择第8个采样点,通过一个点来判断这个bit的高低电平,这种方法判断你可能感觉不太合理,但是我告诉你,小华半导体HC32F4就是这样设计的,这个后续会讲HC32F4串口的坑

5. 我的数据乱码分析

上面对照者用户手册来分析了串口的识别方式,那现在我们来看一下我为什么在115200的时候会乱码。

现在将我的通信示波器采集的图像放大,如下:
在这里插入图片描述

这是波特率为115200的图像,标准下一个bit时间是8.68us,你会发现我的这个起始位低电平只有8.0us,根据文章《GD32F450的USART接收数据错误问题》博主问FAE可知道,GD32是连续采集16个点全为0,作为起始位。如果是这样,当16倍过采样,采样间隔是8.68us/16 = 0.54us 。而 8.68us-8.0us>0.54,因此这16个采样至少有一次是不正常的,因此起始位数据就会识别错误

在这里我当时有个疑问,现在我们都知道我的数据乱码是因为串口在识别起始位的时候出现了问题,可是GD32F4的串口有两种模式通过OSB=0或=1来设置,那么这两种模式起始位都是这样识别的吗?于是我再次实验:

gd32f4xx_usart.c有配置OSB位的函数,如下:

/*!
    \brief    configure sample bit method
    \param[in]  usart_periph: USARTx(x=0,1,2,5)/UARTx(x=3,4,6,7)
    \param[in]  obsm: sample bit
                only one parameter can be selected which is shown as below:
      \arg        USART_OSB_1bit: 1 bit
      \arg        USART_OSB_3bit: 3 bits
    \param[out] none
    \retval     none
*/
void usart_sample_bit_config(uint32_t usart_periph, uint32_t obsm)
{
    
    
    USART_CTL2(usart_periph) &= ~(USART_CTL2_OSB);
    USART_CTL2(usart_periph) |= obsm;
}

我在初始化串口的时候,添加上面函数的设置,结果还是乱码,这就说明,不管OSB = 1还是OSB = 0,起始位的判断都是有问题的。

后来我反复的确认,这个bit出现低电平变短,高电平变长的原因是我的那个USB转rs422模块产生的,当我将我两个开发板的RS422互联,就不会出现问题,这就说明并不是所有品牌的RS485或422会出现bit时常低电平变短,高电平变长的现象

下图是使用CA-IS3086W,会发现数据很正常,如下图:
在这里插入图片描述

现在有个非常尬的事:我们设计RS422是对接别人的接口,我们也不知道它用的什么芯片,而且到时候它接在STM32的串口就能用,接在你的设备上就不能,你说是他的电平不标准,谁信呀

后来我用了我以前在淘宝买的很便宜的黑壳子的usb转485,结果非常好用,买的贵的反而不行,便宜的反而好用,如下:
在这里插入图片描述

6. 总结

当我们在型号替换的时候,千万不要想当然,即使是像串口这么简单的外设,都会因为各家的实现差异导致翻车,因此在换型前,一定要测试实践

串口协议虽然有标准,可是貌似没有bit时间容错的标准,因此每家的mcu对此兼容性不同,我们不能说GD的uart做的不好,只能说它的兼容性比STM32差的有点多,更何况RS485和RS422转换芯片众多,兼容更多更广的设备,才能有更好的认可。

我的项目结果,因为上面的问题根本没办法改善,我只能更换mcu厂家,所以现在我决定这个项目用小华半导体HC32FA0重做,然后又进新坑。

同时我也感谢我在淘宝买的那个不能发出标准报文的usb转422/485模块,因为它替我避免了批量的损失。

猜你喜欢

转载自blog.csdn.net/Zhichao_Zhang/article/details/128046411