duke000
308 天前
做为 UART 接收方,一般是在一个 bit 的中间位置采样数据。对应你引用的图片的时钟波形,在波形上升沿的地方采样,且启动位和停止位也应该有一样的波形才对(图中没有),等停止位的中间采样完成后,接收方的状态机就已经跳转到空闲了,等待下一次接收,所以在 0 等待的情况下,正常不会有长时间发送产生累积误差的问题。因为停止位的后一半时间就是可以用来消除累积误差的。(不能排除所有芯片都设计没有问题,这里能出问题的概率非常小。)
至于分隔数据包,一般有两种做法:
一是使用 1 、2 个字节的空闲时间来分隔,譬如 MODBUS 、CDBUS 等协议
另一种是用特殊的帧头来分隔:譬如 PPP 、以及很多私有协议,譬如 FF AA 开头之类的
其实还可以使用串口特殊字符 break 字符来分隔,只是没见有人这样用,break 字符是连续至少 1 个字节时间的低电平(相当于正常数据 0x00 的停止位也强制为 0 )
使用特殊帧头又会涉及到数据和帧头重复的问题,PPP 协议要求数据要转译,MCU 处理很麻烦、低效。如果要避免你说的没有空闲字节导致接收错位的问题,一般软件层面可以有一些流控机制,譬如发送一堆数据后要有回复,没收到回复等超时重新传输。而这个超时就是一种可以隔开数据包的空闲时间。
我个人是倾向直接使用空闲来分隔数据包,实时性高很多,通用性也就更好。即便是实时性不高的设备,譬如电脑接收 MODBUS 、CDBUS 等协议,数据包粘到一起,也没有关系,按照帧的定义一样可以正确解析所有数据包。(万一出问题,可能是数据包错位,可以逐字节遍历尝试重新解包,直到能解出正确的包。但我建议直接清空接收缓存,等待接收新的数据包。)
除了普通按字节为单位收发的 UART 硬件,也有能按数据包为单位来收发的串口芯片,譬如 CDCTL01A ,可以让 RS485 和 CAN 一样支持仲裁,支持多主对等通讯,可以把半双工的 RS485 当作全双工来用,速率可以达到 50Mbps, 芯片本身是开源的,你可以参考一下其 verilog 代码实现。