串口接收心酸史(闲话)

以下内容为本人接触串口数据接收的一个心路历程的回顾,口水话比较多,算是一点经验吧。写这篇笔记的内容是当作自己对串口数据处理的一个回顾,也希望能够对后面接触相应内容的人一些帮助。

第一阶段:轮询接收

在刚开始接触串口的时候,自己只会从中断里面将数据读取到一个数组中进行缓存,使用的时候应用程序从这个数组中拿取数据。这样操作串口数据会存在这样的问题:你不知道你期待数据什么时候到来。这时候就需要我们在后台程序运行的时候时不时过来判断一下接收数组中有没有我们想要的数据。这是我刚接触串口时想到的串口数据处理方法。这种方法实现起来有点呆,第一,代码逻辑很混乱,将串口接收判断和主函数写在了一起;第二,会造成数据丢失的风险,当你在主程序中执行相应的操作时间比较长的时候,而在这是,期待的串口数据刚好来到,就会错过这条数据从而造成数据丢失。实际过程中基本不会这么处理串口数据。

第二阶段:中断处理

这个阶段我将判断数据内容的工作放在了中断中具体做法是这样子的:

用一个数组在中断中接收串口数据,在接收完一个字节数据之后判断已接收到的数据中有没有我想要的数据(当时刚好接触strstr这个函数),如果有的话就调用相应的处理函数或者立起的标志位,然后主函数中判断相应的标志位从而处理数据。

这个阶段是我使用过得最久的一个方法,但是也是最痛苦最纠结我的一个阶段。

我经常会碰到这样的情况:相应的标志位已经触发了,但是读取数据是拿到的数据却不是我想要的数据,原因是我立起标志位之后又有串口数据将接收数据填补了,到我来处理数据时,我拿到的已经不是我想要的数据了。这种情况比数据丢失还难受。

还有一种情况是,当你在中断中判断字符串的时候,串口还是会源源不断的来数据,而这时候你在干嘛,在判断接受数组中有没有你想要的数据,那么这时候你就不能把串口新来的数据接收起来,这样就会丢掉后面的数据,从而造成数据丢失。所以千万不要在中断里面执行什么操作,中断要快进快出,在中断里面进行字符串判断,中断资源快速响应的特点就丢掉了。

当时自己为什么会这么做呢?因为我只会这么做)))(太菜了,呜呜呜)这种方法是在买4G模块的配套例程里面的,然后自己就用在了智能安全驾驶的项目里面去了。导致的问题是我的硬件总是不能响应服务器下发的数据,比如,服务器下发的数据要求我播放相应的语音,而我这边经常丢失数据,或者没有拿到完整的数据而没有任何反应。结果就是,比赛拍视频的时候我们只能不断的试,直到它触发为止🤪

现在回想起来那时候真的难受,知道是由于串口数据丢失导致的,但是自己不知道应该怎么解决,百度也因为自己的关键词弄错了而没有得到想要的结果,评价就是,真的很菜!

第三阶段:环形缓冲区+RTOS

这个时候接触了实时操作系统了,感觉就非常nice!当时主要是在处理AT指令的时候让人很头疼,就很幸运接触了韦东山的MQTT课程,才了解到这种串口数据的处理方法,当时就很高兴,但是也没怎么处理好串口数据,但是相比之前已经有很大的提升了。下面大概讲一下这种方法怎么实现串口接收

首先构造一个环形队列,作为缓冲区,串口有数据就通过中断将数据放入缓冲区,这样可以一定程度上避免数据丢失。然后用一个线程负责从缓冲区中读取数据并且解析,如果数据中有相应的标志位的话就把数据存到相应的位置或者通知相应的线程触发相应的操作。

这个方法的优势在于不用死等串口数据,通过多线程机制,主线程没有收到通知的时候就干自己的事情,当收到串口数据解析线程的通知时再执行其他的操作。还有一个就是,环形缓冲区会记录收到的所有数据,数据会通过环形缓冲区再传递给串口数据解析线程,只要解析线程的处理速度大于串口数据的接收速度,就能避免数据丢失。

在这个阶段,我接触到了RTOS,极大的提高的系统运行的实时性,也就解决了中断接收时遇到的数据会被新数据覆盖的情况,通过缓冲区,又解决数据丢失的问题。所以,在现在的我看来,如果要解析比较麻烦的数据,还是要上操作系统比较方便。

第四阶段:帧头帧尾判断

其实这种方法应该是串口数据接收处理的最有效的方法。上面经历过的三个阶段都没有在数据中加入帧分割信息来的有效。

在传输的信息的前面和后面加入一些特殊字符,那么当你处理串口数据的时候,只要判断有没有收到帧头特殊字符,收到了就开始接收后面的字符,否则就丢弃,收到了帧尾信息时,代表信息接收完毕,这时候就可以通知相应的主程序对数据进行处理了。

这么简单有效的方法之前我居然一直想不到,就很难受。不过这种方法我还没有实践过,但是有了思维就很好,很愉悦。在后面应该会一直使用这种方法来处理串口的数据,当然应该会和操作系统一起搭配。

心得

接触串口应该有一年了,现在回想起来,其实这个东西也没有那么复杂。如果当初自己一开始就接触的是帧头帧尾处理数据的方法,也许就不会有那么多的坎坷了。网上的教程对于串口数据的处理这部分内容还是比较少,只是讲了怎么将数据接收起来,但是数据怎么处理却没有怎么说明。这应该算是STM32应用层面的内容了。自己当时局限性太大了,连一些专有的名词都没有接触过,所以慢慢摸索,走了很长很长的路。

还有一点就是,自己以前学习STM32太纠结于相应的硬件驱动怎么实现的这些细节了,眼光没有放到应用层这个高度上,导致浪费了好多时间在一些无关紧要的细节上。

现在的我看来,学习单片机或者说嵌入式,应该把重点放在应用上。要多学习一些程序框架,算法思想,以及一些巧妙的处理方法,而不是纠结于底层两行代码实现的区别上。

希望能给后来人带来一点帮助,不要重复地做没有意义的工作。

0%