关于串口通信协议的解析,该怎么解决
串口通信协议
附图
通常是这样处理的:
1.设置一个循环缓冲区.
2.串口接收的数据先存入循环缓冲区中,修改写指针位置.
3.设置协议对象,扫描循环缓冲区中的特征字节(一般是报头).找到了然后看循环缓冲区读写指针的距离是否够一帧数据.
4.如果够一帧长度,则从报头按照报文长度进行数据校验和解析.
5.修改读指针位置.
注意,你可以通过单独的线程处理串口数据写入循环缓冲区.
帧头标志 版本号 类别 帧头校验和 帧号
数据总长度 保留
数据CRC校验 数据区
数据区
以上是一个帧的大致结构,在该协议中有以下七类帧,数据帧、压缩数据帧数据应答帧、检测帧、检测应答帧、系统错误帧、ABORT帧,这里面还有接受和发送的之间的同步,异步的问题。帧与帧之间的状态转化等等!
1.实现串口通信三种方式:串口控件 ,串口类,api函数。用那种实现 要好点?
2.我的问题的 怎么将数据组织成一帧,接受怎么将帧解析出来?
------解决方案--------------------
1、API,灵活
2、定义结构,C字符串操作,#program pack(1)即可
------解决方案--------------------
不用控件,自己用api来实现
------解决方案--------------------
1.建议使用API或串口类都可以,控件的发布太麻烦
2.定义两个函数一个封装成帧一个拆帧,串口接受数据的时候判断,当发现接受完一帧就去拆帧解析数据就OK了
------解决方案--------------------
可以用帧尾或帧的结束符判断是否接收完一帧的,接收完一帧,就进入拆帧函数,根据你的帧的类别进行拆帧
------解决方案--------------------
在网上找一个串口类吧。很多的。
至少怎么解释数据,那是基础知识,你应该随便去找本C的基础书看,而不是跑这来问。
------解决方案--------------------
最终发往串口的是字节流。结构体定义与帧格式一致。发送时将结构体转成byte直接往串口发。收的时候策略时根据帧头来,读到帧头后,根据帧格式来得到帧长度。不足长度时,暂存起来等待下次接收(你不可能每次恰好接收一帧吧),下次接收时和暂存区域合并,再次判断帧长度直到足够完整一帧了(若超过完整一帧长,将下一个帧头后内容暂存),完整后开始解析。若数据量较大,建议另开一线程专门解析。线程同步用加锁的方式,取得完整帧加到解析线程缓冲区,解析线程从缓冲区读帧解析,注意线程同步,避免同时操作缓冲区引起异常。。。。。说了一大堆,明白?
------解决方案--------------------
API和串口类都可以,
解析的话可以先读取了固定长度的部分,也就是数据区前面........然后校验帧头,读取数据区长度,把数据区读入。然后校验数据区............
------解决方案--------------------
重要的是接受处理!
每次接受的数据都存到buffer里,
然后根据串口协议从头开始找, 找到第一完整的帧, 解析, 清理buffer中这个帧的数据.
至于解析过程:
首先判断帧头, 不对扔, 找到帧头后根据长度和校验位取出一个完整的包, 如果长度不够, 等待下次数据来后重新解析.
如何处理不定长数据的接收
在处理串口通讯时,经常会遇到不定长数据的接收。由于通讯任务不同及编程要求的差异所以采用的方法也有所不同。本文就此问题进行探讨。不定长数据从数据格式上分,可分为有格式和无格式。
一、无格式不定长数据的接收
这种格式在实际串口通讯中用得不多,一般只用传送字符串数据。问题在于怎么判断接收结束。一般用时间延迟的方法解决。
A、对于非握手式通讯,可用一个定时器定时轮循接收,并假定每个轮循接收完成。用ONCOMM事件接收也可,只是不如定时器定时轮循接收简便。
B、对于握手方式通讯,可用直接轮循法提高接收的准确性。下面是实现此法的函数:
Function sComm(sCommand As String, comReceive As MSComm) As String
Dim nReceiveCount As Integer
If comReceive.PortOpen = False Then
comReceive.PortOpen = True
End If
comReceive.Output = sCommand
Do
nReceiveCount = comReceive.InBufferCount
sleep (2) 'API 函数,挂起当前进程一段时间
Loop Until comReceive.InBufferCount = nReceiveCount
If comReceive.PortOpen = True Then
sComm = comReceive.Input
End If
End Function
注:此函数参照了xth一文。
此法一般是能确保数据接收的正确,但由于WINDOWS是多任务操作系统,当有耗时的进程运行时会丢失数据。如果系统会出现这种情况,可增大函数sleep()的参数值。
二、不定长格式数据的接收
对于不定长数据接收最好的方法是制定通讯协议,比如定义开始字符和结束字符。由于单片机系统通讯一般不太复杂,没必要去制定一套象通用计算机间通讯的协议,而根据单片机系统的大小和性能要求制定通讯协议。实际上为便于交流、维护以及一致性,可制定一套可伸缩的通讯协议。定义了开始字符和结束字符就容易实现不定长格式数据通讯,但在实际通讯编程还是容易出现一些比较隐蔽的通讯错误。下面就常用方法分别进行分析。
A、定时器轮循法。
假定每个轮循期数据接收完毕,并在每个轮循期处理数据,由于有开始字符和结束字符很容易确定接收数据的完整性。好象合理设定轮循时间值就万无一失了,但被动接收数据时无论如何也找不合适的轮循时间值,因为启动定时器和数据到来基本不同步,这就会出现一次发送的数据被分在两个轮循期接收,所以被动接收数据时不能假定每个轮循期数据接收完毕。在接收到结束字符后才确定一次数据接收完毕就可解决此问题。
B、OnComm事件法。
方法和定时器轮循法基本相同,因为每次OnCommg事件也只能接收到一部分数据。在VB的在线帮助中这样注解“设置 Rthreshold 为 1,接收缓冲区收到每一个字符都会使 MSComm 控件产生 OnComm 事件。”。但实际上OnComm事件并不是每收到一个字符便触发一次 OnComm 事件。OnComm事件是在缓冲区收到几个甚至几十个字节数据后才被触发的。版主认为这是WINDOWS多任务使操作系统不能实时响应造成的。如果要在每次OnComm事件接收一个字符似乎可设INPUTLEN属性为1,但实际行不通。VB在线帮助中“有该属性在从输出格式为定长数据的机器读取数据时非常有用”的注解,好象在说对定长字符有效,但版主发现INPUTLEN设为16,接收16个字符定长数据时却被当作两次接收了,一次12个,一次4个。建议在OnComm事件中接收数据要定义通讯协议并检测数据的完整性。 对于不定长格式数据的接收程序员更喜欢定时器轮循法,也许OnComm事件不好控制吧。
对于不定长数据的接收,最佳方法可能是在OnComm事件中启动定时器轮循接收,并同时停止OnComm事件的触发,接收完毕后或超时开启OnComm事件。