在嵌入式领域,数据通信是系统中必不可少的部分,对通信数据的收发处理方式无疑是影响系统稳定性的一大因素,在多年的嵌入式软件开发工作中,几乎每个项目都会接触到这一块,曾经以为很简单,但也正由于对它的轻视吃过不少亏。
印象最深刻的一次是,开发试验阶段通讯收发十分正常,无任何问题,可正式上线之后,经过长时间的运行,就偶尔出现卡死,通信中断,板卡因通信问题而自动复位的现象,这种问题显然不是逻辑问题,因为它是偶然出现的,要解决也不容易再现,极其隐蔽,所以让人很是头疼,花了几个月时间才终于找到原因,现总结如下,以免将来再犯类似错误;
一般通信不管是用什么物理方式,如RS232、485、CAN、网口等,都是将数据首先定义成意义明确的帧,每帧数据大体上都包含帧头、命令字、长度域、有效数据域、校验域、结束符等这几个部分,收发双方都遵循一个固定的帧格式。发送比较简单,将数据打包组成完整帧之后,往外发送就行了,但接收方则相对麻烦一点,因为有些时候是一次读一个字节,有时候一次可以读很多字节,以何种方式来接收并组包比较好呢,相信有经验的工程师肯定能想到,接收必须得要有缓存,即将数据先全部存到一个缓冲区中,接收并缓存的操作与解析组包处理的操作要独立分开,不能在一起操作,这是最重要的。
接收缓存一般可以用环形缓冲区,即依次往缓存区中存放数据,缓冲区满之后又从头开始存放,定义两个指针分别记录存和取数据的地址,存的时候头指针往后移动,取的时候尾指针往后移,这样互不干扰,存取的时候只要记得判定指针极限大小就不会有问题,两个指针都是到头了就归零,永远取两指针之间的数据就是我们尚未处理的数据。
通过尾指针取出数据,我们就可对其做帧格式的解析和判定,从而提取出有效数据,经长时间的验证,这种方式是比较稳定和可靠的。
曾经让我栽过大跟头的是,在取数据时,有时候缓冲区已经有很多数据了,将其一一取出,去做格式解析,有可能这些数据长度是大于一帧的,这时必须在解析一帧之后,就停止取数据,否则缓冲区中数据就会丢失,造成不可知的问题。