【技术贴】串口数据的处理方法

        无论是PC、嵌入式处理器还是单片机,串口都是最重要的接口之一。但是串口PC和嵌入式处理器的底层串口数据由系统驱动预先进行处理,此处仅针对单片机的串口数据处理进行讨论。就我所知的型号来说,比较老的一些单片机,可能没有硬件SPI,可能没有硬件IIC,但是硬件的串口是一定有的,由此可见串口的重要性。

       串口是单片机初学者必学的重要内容,然而,大量的教程中,给出的例程极其简单,可能仅仅是简单地原样发回接收到的数据,完全不能满足实际应用中串口数据处理的需要。

        本文将结合个人经验,进行一些讨论。并提供一种简单的,可以充分复用代码的,串口数据处理逻辑。为了帮助可能阅读本文的初学者理解,从比较基础的内容讲起。

1、串口的电气连接和底层封装

        即使是初学者也应该已经了解,集成芯片与外围电路的交互,是通过集成芯片的金属引脚实现的。在数字电路中,用一个较高范围的电压信号表示1,用较低范围的电压信号表示0;而在模拟电路中,数值连续的电压信号有效。串口显然属于数字电路的范畴。

MCU与外围电路的连接

        串口的连接方式,与普通的GPIO连接没有什么不同。串口通信的过程是单向的,收发对应,因此,需要双向通信的场合,串口连接往往是成对的,如图。串口数据在电气上的传输过程和普通GPIO没什么不同,仅有0和1两个有效的值,如果要传输一个字节,那么必然要将一个字节的8个二进制位拆分,按照顺序进行传输。传输过程完全可以用程序控制GPIO实现,这样做显然是比较麻烦的。索性,在单片机内部通常集成了硬件实现的串口控制器,将IO的控制操作封装起来。正确配置之后,硬件自动完成最小单位数据的发送和接收,可以是9位二进制数据,也可以是8位二进制数据,通常使用8位的数据配置,也就是单次最少传输1个字节数据。面向程序操作,仅提供写入一个字节的寄存器和读取一个字节的寄存器,大大简化了程序控制的复杂度,降低CPU占用,编程无需考虑一个字节传输过程中的细节。尽管串口控制器集成收发功能,单独使用发送和接收、或者分别使用发送和接收都是完全可以的。

通常的串口电气连接与硬件串口的封装

2、串口数据的处理逻辑

        串口单次传输一个字节的数据,在大部分场景下,单个字节的数据长度都是不够用的,需要对分别传输的多个字节进行拼接和处理,以提取所需的数据。可以认为某次想要传输的全部字节,是一个数据包。对于发送端,数据包的划分和数据格式,是主动进行处理的,没有疑问;而对于接收端来说,数据的接收是随机的,其中可能出现中断、丢失、错误,如何处理接收到的字节,才能正确提取数据,排除偶然的错误,是需要斟酌的。

        一般教程仅涉及单字节数据的传输过程,仅做简单地收发例程,如图。

一般串口例程逻辑过程

        为了正确地分割数据包并处理数据,一般会在数据包中添加特殊的标记。添加特殊标记的具体实现可以自行协定,其本质是一样的。常用的一些方法有,添加特殊的包头,例如特殊字符或者指定的多个特定字节的组合;添加包尾;添加描述包长度的字段,根据已知的包长度缓存指定个数的字节。在易受干扰的场合,还应该添加根据数据包内容采用指定算法计算得到的校验字段,在接收端重复相同的计算过程,比较校验值是否一致,如果不一致,则抛弃该数据包。常用的校验算法有校验和算法、CRC校验算法等。

添加特殊标记进行分包
事实上,在实际应用中,往往存在天然的分包。一般情况下,串口传输的数据都不是持续传输的,串口传输的速度比较快,一段数据发送完毕,下一段数据发送之间,存在一段时间间隔,这是天然存在的分包标记。利用时间间隔进行数据的分包,无需增加数据量,也可以配合添加特殊标记的方法,一次代码多次使用,在大部分情况下,甚至不需要修改。实现方法如图。
以时间间隔为标记进行分包的实现

        以时间间隔为标记进行分包的实现,涉及到两个中断,定时中断和接收中断,涉及到两个标识位,接收状态标志位和计时标识位。可用三个函数实现整个接收过程,计时函数放在定时中断,接收中断函数将接收到的数据转存到缓存数组,在main函数的循环处理中,检查接收状态标识位是否指示接收完成,并进行后续的数据分析。可以配合其他方法来使用。

        此方法非常适合于cortex-M内核单片机,cortex-M内核的SysTick定时器每1ms产生一个中断,正好适合用来做定时,触发时间可以定为数毫秒到数十毫秒,可根据实际情况确定。

        手头没有源码,暂时不提供例程。

        欢迎扫码关注我的微信公众号。

微信公众号二维码