APP下载

C#串口高效可靠的接收方案设计

2018-12-06刘马飞

物联网技术 2018年8期
关键词:响应函数缓冲区字节

刘马飞

摘 要:在事件触发方式接收串口数据包时,尤其在数据包不定长的情况下,需要仔细设计接收方案,否则会出现数据包接收不完整的情况。文中介绍了一种C#平台下串口数据包的接收方案,可高效可靠地接收串口数据包,对C#串口应用程序的设计开发具有指导意义。

关键词:C#;RS 232;串口通信;数据接收

中图分类号:TP302 文献标识码:A 文章编号:2095-1302(2018)08-00-03

0 引 言

C#.NET提供SerialPort类进行串口数据收发通信。C#串口编程是职业教育物联网应用技术专业资源库主干课程《物联网设备编程与实施》的核心内容之一[1]。在使用SerialPort进行数据接收时,面临着“不知何时读”的困境,通常采用系统封装的事件触发方式进行数据接收[2],即C# SerialPort类封装了DataReceived事件,当串口接收缓冲区收到数据的字节数超过SerialPort串口属性ReceivedBytesThreshold的值时,系统将触发DataReceived事件,调用该事件的响应函数,因此,可在该事件的响应函数中进行串口数据接收操作[1]。本文介绍了常规的DataReceived事件驱动数据接收方法,提出了一种高效可靠的数据接收方案,并对可靠性进行了仿真验证。

1 C#串口常见数据接收方案

C#串口常见数据接收方法为在DataReceived事件响应函数中,首先查询接收缓冲区的字节数,然后申请一段字节数组的内存空间,再调用SerialPort对象SPCOM的Read函数,将串口接收缓冲区的数据读取到字节数组中,最后对字节数组进行处理。

串口通信设备传递的数据包通常为不定长数据包,因此ReceivedBytesThreshold通常取默认值1,表示串口接收缓冲区的字节数大于或等于1便触发DataReceived事件。由于DataReceived事件的触发和处理运行在辅助线程上,DataReceived事件触发与DataReceived事件被处理而调用响应函数之间存在微小的时延。因此,当串口接收一个数据包时,可能出现在收到数据包第一个字节时触发DataReceived事件,而当该DataReceived事件被处理时,数据包并未接收完毕;也可能出现串口接收一个数据包时,触发多次DataReceived事件的情况。在串口数据包出现时间间隔较大的情况下,可以采用一般可靠的方法,即在进行串口数据接收操作之前,调用Thread.Sleep(100)休眠100 ms后,再进行数据接收操作,如此一来便降低了程序的响应速度[3-4]。操作程序如下:

private void spCOM_DataReceived(object sender,SerialData ReceivedEventArgs e)

{

Thread.Sleep(100)//數据接收操作先休眠100 ms

//进行串口数据接收操作

int icount = spCOM.BytesToRead;

byte[] data = new byte[icount];

spCOM.Read(data,0,icount);

//对数据包进行处理操作

}

数据包通常包含有一定的包头和包结束标志,用于表征数据包的完整性。对于数据包的处理,必须在接收到完整数据包的前提下方可进行。当较多数据包到达间隔接近或过长时,使其休眠一段时间的方式可能并不奏效,如果简单判断包头结束标志不正确就丢弃数据,可能导致丢包,因此需要采用高效可靠的接收方案。

2 C#串口高效可靠的数据接收方案

根据上述分析,串口数据接收方案的高效性要求当串口接收缓冲区存在数据时,需要立即进行数据接收操作,因此串口控件的ReceivedBytesThreshold属性取默认值1,且在DataReceived事件响应函数中接收串口数据前不进行线程休眠。为了避免数据包接收不完整的情况出现,需要应用程序对串口接收到的数据重新组装,精确定位数据包的开头和结尾,再进行数据包的处理,从而实现数据接收的可靠性。

2.1 串口数据报文格式

本文以串口接收思远创智能设备10系列高频RFID全协议读写器的数据包为例,阐述接收方案。该读写器返回的数据包长度不固定,其格式如图1所示。

2.2 高效可靠接收的实现

为了对接收到的串口数据包重新组装,需要应用程序创建缓冲区。首先将接收到的串口数据填充到接收缓冲区,然后在接收缓冲区从前往后搜索包开始标记STX与接收标记ETX,从而可以获得完整数据包。方案实现步骤如下:

(1)应用程序将创建类型为字节的泛型列表对象作为程序缓冲区,即在窗体成员变量中定义List recv_buf = new List()。

(2)在DataReceived事件响应函数中,首先定义两个布尔变量data_sta_catched与data_end_catched,表示是否已经寻找到数据包头和数据包结束标志,然后将串口接收缓冲区中的数据添加到程序缓冲区。

(3)判断程序缓冲区是否包含一个完整的数据包。判断步骤如下:

①由于数据包的大小必然大于或等于6 B,因此,首先判断程序缓冲区字节数是否大于或等于6。若条件满足,则进行后续判断;否则,结束判断。

②在程序缓冲区从前往后寻找数据包头STX(0x02),对于非数据包头的数据,将其移出程序缓冲区,确保寻找到的数据包头位于程序缓冲区的开始位置。寻找到数据包头后,将data_sta_catched置为True,并结束寻找。

③若已成功寻找到数据包头,则检查数据包结束标志以确定是否已经收到完整数据包。由于数据包头STX位于程序缓冲的开始位置,程序缓冲的第三个字节为数据包的DATALENGTH字段,表征了数据包中数据字节的长度,即包括STATUS 和DATA 域的字节数,因此本数据包的总长度应在DATALENGTH字段值上加5。

可首先通过判断程序缓冲区中的字节数是否大于或等于当前数据包的总长度。若条件满足,则通过DATALENGTH字段推断数据包结束字节位置,并判断该字节是否为数据包结束标志ETX(0x03)。若该字节为数据包结束标志,表明成功寻找到了数据包,则置data_end_catched为True,并确定数据包的长度len_packet;若该字节不为数据包结束标志,则可断定②中data_sta_catched并非真正的数据包开头,因此删除该伪数据包头,并置data_sta_catched为False。

④判断data_sta_catched和data_end_catched是否均为True,若条件满足,则程序缓冲区从字节0位置开始已包含一个完整的数据包,该数据包长度为len_packet,因此便可对该数据包进行处理,处理完毕后需要将该数据包从程序缓冲区中删除。

方案的实现代码如下:

private void spCOM_DataReceived(object sender,SerialData ReceivedEventArgs e)

{//定义两个标志,记录是否找到数据包开始和数据包结束

bool data_sta_catched=false;

bool data_end_catched=false;

//把本次数据添加到接收缓冲中

int iCount = 0,idx;

iCount = spCOM.BytesToRead;

byte[] bData = new byte[iCount];

spCOM.Read(bData,0,iCount);

recv_buf.AddRange(bData);

//尋找数据包的开始位置和结束位置,数据包大小必然等于6

int len_packet=0;

if(recv_buf.Count >= 6)//判断程序缓冲区是否大于6

{

while(recv_buf.Count > 0)//从前往后寻找数据包头0x02

{

if(recv_buf[0] == 2)

{

data_sta_catched = true;

break;

}

else

{

recv_buf.RemoveAt(0);

}

}

//找到数据包头后,再来检查是否已经收到完整数据包

if(data_sta_catched)

{

iCount= Convert.ToInt32(recv_buf[2]);

if(recv_buf.Count >= iCount + 5)

{

if(recv_buf[iCount + 4] == 3)

{

data_end_catched = true;

len_packet = iCount + 5;

}

else

{

recv_buf.RemoveAt(0);

data_sta_catched = false;

}

}

}

}

//收到完整数据包,解析数据包

if(data_sta_catched&& data_end_catched)

{

//对数据包进行处理,然后将该数据包从缓冲区中移除

recv_buf.RemoveRange(0,len_packet);

}

}

方案验证:

由于接收操作摒弃了常规方法中的增加线程休眠方式,因此数据接收的高效性通过Windows线程并发得以保证,读者可将方案在C#串口通信程序中实现,观察接收数据的实

时性。

为了验证接收方案的可靠性,避免数据中伪数据包头和伪数据包结束标志对数据包接收造成干扰而引起丢包,避免硬件电路中热噪声对接收方案的可靠性检测产生干扰,采用虚拟串口软件创建一对虚拟串口COM1和COM2进行模拟。测试程序中创建发送线程不间断发送100 000个不定长的数据包到COM1,然后利用本文接收方案在COM2上进行串口数据接收,可成功接收到100 000个数据包。

从测试结果可以看出,本文接收方案成功避免了数据中伪数据包头和伪数据包结束标志对数据包接收造成干扰而引起丢包的现象,从而证明该接收方案具有高可靠性。

3 结 语

本文介绍了一种在C#平台下串口数据包的接收方案,通过应用程序增加缓冲区对数据包重组,避免了简单接收时数据包丢失的不足,可高效、可靠地接收串口数据包,对C#串口应用程序的设计开发具有指导意义。

参考文献

[1]邱晓荣.《物联网设备编程与实施》课程的构建与实施[J].物联网技术,2015,5(7):96-97.

[2]陈天娥.物联网设备编程与实施[M].北京:高等教育出版社,2014.

[3] NAGEL C,GLYNN J,SKINNER M. C#高级编程(9版)[M].

李铭,译.北京:清华大学出版社,2015.

[4] PERKINS B , HAMMER J V , REID J D. C#入门经典(7版)[M].齐立波,黄俊伟,译.北京:清华大学出版社,2016.

[5]于润伟. C#项目实训教程[M].北京:电子工业出版社,2009.

[6]高超.组合导航计算机高效多串口通讯技术的设计与实现[J].数字技术与应用,2016(1):197.

[7]王斌,张林,邓军.一种基于高速串口通信的高效数据处理方法[J].自动化技术与应用,2016,35(6):57-60.

[8]郑武,肖宝森.串口通信新模型的研究与C#实现[J].电脑编程技巧与维护,2013(13):29-30.

猜你喜欢

响应函数缓冲区字节
一类具有Beddington-DeAngelis响应函数的阶段结构捕食模型的稳定性
No.8 字节跳动将推出独立出口电商APP
No.10 “字节跳动手机”要来了?
相机响应函数定标的正则化方法
嫩江重要省界缓冲区水质单因子评价法研究
简谈MC7字节码
克服动态问题影响的相机响应函数标定
关键链技术缓冲区的确定方法研究
地理信息系统绘图缓冲区技术设计与实现
AVS标准中的视频码流缓冲区校验模型分析