本帖最后由 王昱顺 于 2024-9-27 08:33 编辑
串口通信,作为嵌入式领域常见通讯方式之一,应用相当广泛。常用于各种模块之间的通讯,以及调试使用。不过,串口本身的抗干扰并不是很好,如果遇到线长一些或者因为接触不良造成信号数据包丢失的情况,普通的直接传输方式就分辨不出来,容易造成数据混乱了。 下面就来介绍一些常用的几种可以过滤某几个数据丢失,或者传输错误的处理方式。 首先从硬件层面来讲,串口发送的数据包一般都不是连续的,以这个特点出发,就可以使用定时器手动实现串口接收的超时分包。或者使用带有串口超时功能的芯片,比如最新的AI8051U、STC8H2K08U,通过设置超时中断功能实现分包。但是此时还不能分辨是不是漏掉了数据包,还需要加入校验。如果数据包内数据不多,可以直接使用ADD8校验(所有数据加起来,取低八位),或者按照实际需求,使用CRC16之类的常见算法。此时,如果数据丢失或者某几个数据位错误,即可通过跟校验位计算得到是否存在数据缺失问题。 比如下面举一个例子,使用ADD8算法,发送的数据包是 00 01 02 03 06其中,最后一个06是前面所有数据位的和 如果数据受到了干扰,变成了 01 01 02 03 06,那么前四个数据位计算的校验结果就是07,和06比较发现不对,即可丢弃当前数据包 如果因为接口松动、干扰等问题丢失了一个数据包,变成了 00 01 03 06 00(不够的位,不改变就是0) 此时,按照校验计算,前四个数据位的和就是0a,与最后的00不符合,也能发现问题,然后丢弃数据包。 但是这种传输方式要求串口的包与包之间需要带有一定的停顿来触发超时中断,对于遥控类或者实时数据传输类型的数据,如果想要持续不中断的发送的情况,就可以使用包头方式进行识别了。 那么,没有了超时中断来进行分包,应该如何分辨坏数据和丢数据呢?甚至说,如果数据内容里有和包头一致的数据,会不会被识别成包头导致错误?下面来细细分析。 首先需要确定的就是,包头方式不大适合变长数据发送,不然有可能错误识别到异常的长度数据,导致相当长一段的数据失效。 这里,直接来举一个例子说明包头方式如何分辨数据包的。 假设数据包的包头为aa,使用ADD8进行校验,带校验位总长度为5个字节,校验包括包头。 那么,发送的数据就是这个样子的: aa 00 01 02 ad 最后的ad为aa+01+02的和。 上面已经展示过了校验位可以排除掉数据丢失或者异常的情况,这里就直接展示如何从一串数据流中读取到上面这段数据 假设数据流为: 00 33 aa 02 aa 00 01 02 ad aa 00 01 02 ad 首先程序从头开始搜索aa数据,第一次搜索到的是 aa 02 aa 00 01,此时经过计算,01校验位和前面的数据位不和,丢弃数据包(此时的数据同步还是错误的)。 然后继续向后开始搜索,经过了 02 ad后,再次搜到了一个aa数据头,此时再次读取出一串数据: aa 00 01 02 ad,这里再将ad和前面的数据和进行校验比较,发现数据成功匹配,可以认定为当前帧是有效的了。 这时候,就会发现之前不同步的数据位也神奇的同步回来了,而且数据流中,额外的aa(虚假数据头)也没有被识别成功,仅仅干扰了一个数据包的识别。 这种利用数据头进行重同步的方式,其实相当适合流数据传输,因为数据想要传输的快,就不可避免的受到一些干扰,并且数据位有概率受到污染或者缺失问题。这种问题其实在无线遥控上更为常见一些。
使用这些常见的重同步手段,可以让串口通讯变得更加好用,即使出现了数据丢失和错误,也可以识别和丢弃掉。也就避免了直接使用串口传输数据时,因为偶然的数据丢失造成数据识别混乱。
|