上一次了解了最基本的串行通信。
尽管RS-232本身带有奇偶校验位,但是其检错能力非常有限,同时,在串口的数据传输中,数据出错的可能随着传输距离的增长不断变大。同时,收发两方如何进行同步也是一个需要考虑的问题,为了解决这一系列问题,有一个行之有效的方法——协议。通过增加多余的冗余部分来确保信息可靠的传输。
首先需要解决的问题是帧头与帧尾,用来界定一个完整的帧。在这里我们简单的将帧头与帧尾分别设置为0x02与0x03。在更多的时候,会采用巴格码来设置帧头。主要的目的是避免帧内容中出现了与帧尾相同的字符而导致提前结束。这里我们采用另一种方法来解决这个问题。
在传输的过程中,可能会发生数据丢失的情况,也可能数据过多,接收方还未接收完毕,发送方又进行发送,导致数据溢出等诸多问题。因此,需要有一个方法来避免这种情况的问题。博主选择参考滑动窗口协议的类容,设置一个发送序号与接收序号,只有当确认回复的接收序号与发送序号相同时,才会发送下一帧。同时,若长时间没有收到确认帧,则会重发该数据。
同时,本次串行通讯的应用场景主要是用于控制总机与执行分机之前,因此,需要对帧的类型进行划分,即控制帧(01)与表示帧(10)。
如果没有建立连接就进行发送,可能会导致接收方未曾做好准备,或者,在信息传输的介质出现问题,没有建立连接时发送方可能会陷入不断重发的死循环。为了避免这种问题,可以参考TCP/IP的三次握手方法,建立握手协议来解决。同时也需要设立专门的连接状态字,来进行心跳检查,检验通讯是否正常。
之前提到过,通常的奇偶校验能力有限,当下大多采用CRC循环校验来进行差错检验。因此需要设立CRC校验位。
经过以上分析,我们的通信协议可以简单的设计为:
帧头 | 发送序号 | 确认序号 | 帧类型 | 标志位 | 连接状态 | 数据位 | 校验位 | 帧尾 |
1byte | 4bit | 4bit | 2bit | 2bit | 4bit | 8byte | 4byte | 1byte |
在上一次串口通信的基础上,我们可以编写成帧函数来将我们的数据封装成帧,再将其发送。
因为在程序中采用的是serialport.writeLine的形式,即字符串发送,这里我们用1个字符来代替1个比特进行操作。
首先是确定一些全局变量,用来记录整个通讯状态。
private static bool con = true;//连接状态
private static int i = 1;//发送帧序号
private static int j = 0;//握手标志
private static int reSend = 1;//重发次数
然后根据我们的协议内容依次建立:
string Data = "00000000";//初始化为8个数字
string message = "";
string head = "02";//帧头
string Sendnum = "0"+(i % 8).ToString();//发送帧序号
string Getnum = Sendnum;//接受帧序号
string type = "01";//帧类型
需要说明的是,在对数据的处理我们的数据位为8个字节,若依然用一个字节代替一个比特,会导致数据长度过高,且意义不大,因此,我们用一个字符来代替一个字节。
然后将这些数据依次组合起来,形成帧的前部分,对这前部分进行32位CRC校验得到CRC的校验码,将其作为校验位,最后再加上帧尾。这样我们的帧就设立完毕了,将封装成帧的数据当成一组字符串,通过serialport.writeLine进行发送即可。
同时,在接收方,收到数据后需要对数据进行解析。
我们在提取时,需要知道的信息的数据位以及校验位,以及对数据进行再校验,与校验位进行比较,因此我们分别对这三个部分进行提取:
string getcrc = strRev.Substring(0, 20);//提取接受数据中的代校验位
string Crc = strRev.Substring(20, strRev.Length-22);//提取数据中的校验位
同样,对代校验位进行CRC校验,与校验码进行比较,若一直,则传输正确,反之则丢弃该数据,请求重传。
在未出错的情况下,读取数据位:
string getdata = strRev.Substring(12,8);//提取接受数据中的数据位
由此,则经历了数据成帧-发送-接受-解析等4个过程。
但是本次学习中只是模拟了一个简单的通信过程,整个过程由人工进行参与与设计,但是如何让2台机器自动运行,两台计算机如何进行互动,需要考虑更多的问题。
-------------------------------------------------
本次学习中涉及到的一些问题:
1.C#中string函数的相关操作,本次运用到的是remove与substring。此类操作非常基础,但需要多加练习,不然容易生疏遗忘。
2.本次的CRC校验函数是从网络上获取的源码,只是对CRC的基本工作原理进行了了解,有机会要自己动手进行32CRC校验函数的编写。