C#串口通信时丢失数据的一种解决方法

刘凯 周云耀

武汉理工大学信息工程学院 武汉市(430070

E-mail: lk.6@163.com

摘要:C # 串行类( SerialPort ).NET Framework version 2.0中一个新增的类,该类将串口操作了封装,从而为串口通信提供了简便方法,而且具有功能强大、通信快速、实时性好等特点。但在实际串口通信的应用中,在串口高波特率大信息量的数据通信时,会出现丢失数据的问题。此时如果只是增加串口类的缓存容量是不能根本解决问题的。本文就是从此实际中遇到的问题出发,分析了问题形成的原因,并结合实际开发的经验,给出了一种解决问题的方法。

关键词:C# 串行类 丢失数据 队列

中图分类号:TP311

              1.

前言

C # 串行类( SerialPort ) Visual Studio 2005 中一个新增的类,它为应用程序提供了通过串口收发数据的简便方法。C # 串行类具有功能强大、通信快速、实时性好等特点[1]。该类用于控制串行端口文件资源,提供同步 I/O 和事件驱动的 I/O、对管脚和中断状态的访问以及对串行驱动程序属性的访问。SerialPort 类支持:ASCIIEncodingUTF8Encoding等几乎所有编码格式2

2.

C#串口通信的一般实现方法及潜存的问题

串口有两种读取方式,一种是同步的,另外一种就是基于事件的异步读取方式。因为同步接收会阻塞线程所以在大数据量通信时常采用异步方法读取。

在通信之前要对串口对象做一个初始化,这包括设置PortName(串口号)、BaudRate(波特率)、Parity(奇偶校验)、DataBits(数据位数)等,在此就不赘述了。

由于SerialPort类的封装,屏蔽了很多通信细节。所以异步串口通信的实现逻辑很简单。我们只须要为SerialProt类的DataReceived事件绑定一个处理函数,然后就可以在该函数中实现对串口数据的读取。假设该函数名为GetStrFromPort,其实现示例如下。

Public void GetStrFromPort( object sender, SerialDataReceivedEventArgs e )

{

string str = null;

 

str = serialprot.ReadTo( "/n/r" ); //读到该帧数据结束处

serialport.DiscardInBuffer(); //清除缓存中的内容

DealWithProtStr( str ); //处理接收到的数据

}


- 1 -

大多串口程序都会采用这种思路来实现串口通信。即先接收数据,然后处理数据,并在完成数据处理后,再次等待接收新数据。但这种实现方法在串口高速率大信息量通信时,会出现丢失数据的情况。

数据丢失的原因在于数据接收与数据处理同在一个线程中,如果数据处理时间较长,来不及接收的数据只能暂存于缓存中。一旦缓存满了,新到的数据就会冲刷掉未来的及接收的数据,从而造成数据的丢失。此时如果只单单增加缓存的容量是不能根本解决问题的。这也是我们在实际应用中遇到的问题。

              3.

丢失数据问题的解决办法

有鉴于此,我们解决问题的思路就是将数据接收与数据处理分离开来,使数据接收得到最快的时间响应。通过在实际中的反复实验,我们最终采用了多线程加数据池来解决此问题。

设计思路如下:数据接收与数据处理分别在两个线程中进行,数据接收线程负责数据接收并将接收的数据存入数据池中;数据处理线程负责从数据池中读取数据和处理数据。程序设计思路如图1-1所示。

由图1-1可以看出,两个线程有可能会同时访问数据池。因此为使数据接收得到最快的时间响应,最好不要选用像数组这样数据结构。因为此类数据结构在多线程中操作时必须频繁地加锁解锁,在一定程度上会降低程序的性能。所以我们选用队列Queen作为数据池的数据结构。

队列在顺序存储方面非常有用。数据对象在队列的一端插入,另一端移除。而且当两个线程同时访问队列,如果一个线程只负责数据存入,另一个线程只负责操作数据读取时,不会出现多线程的资源争用的问题,所以不必使用加锁解锁操作,从而提高了程序的运行效率。

 

1-1 多线程加数据池模式的串口通信设计示意图


http://www.paper.edu.cn

       

下面是程序的伪代码。

数据接收线程:

ReceiveThread() { string str = ReceiveFormPort(); //从串口读取数据 queue. Enqueue( str ); //将数据存入队列 }

数据处理线程

DealData()

{

while( true ) //循环检测队列

{

if( queue.Count >= 1 ) //队列中有数据

{

string data = queue.Dequeue(); //将数据出队

DealWithReceiveData( data ); //处理数据

}

}

}

通过这种多线程加数据池的方法,我们就可以将数据接与数据处理独立开来,从而使串口接收事件得到最快的速度响应。从而达到我们消除丢失数据的问题。

4.

结束语

通过利用多线程和数据池,我们解决了C#串口类,在高波特率通信时丢失数据的问题。该设计模式是非常强健的。它在处理高速串口通信时能够最大程度的保证通信的正确性。

 

参考文献:

[1] Schildt H. C # 完全手册》 [M]. 北京:电子工业出版,2005

[2] Microsoft. MSDN 2005(Microsoft Developer Network)

[3] Robison S, Harvey B.Profession C # [M]. America: Wrox Press Inc, 2005.

[4] 李渊博. 《基于WindowsCE.NET的串口通信及应用》.中国科技论文在线,2005

  • 11
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 彻底解决c问题需要分几个方面来考虑。首先,我们需要明确c问题指的是什么,是指编程语言C中的问题还是其他问题。如果是指C编程语言中的问题,可以采取以下措施来彻底解决。 第一,加强C语言的教育和培训。提高C语言的教育质量,培养学生对C语言的理解和掌握能力。同,也要加强C语言的培训,提供更多的实践机会和项目案例,让学生能够通过实际操作来更好地掌握C语言的编程技巧。 第二,加强代码规范和质量管理。制定C语言编程的规范和标准,确保代码的可读性和可维护性。在编程过程中要进行严格的代码审查和测试,确保代码的质量和稳定性。 第三,提供更好的开发工具和环境。不断改进和完善C语言编程的开发工具和环境,提供更好的编译器、调试器、集成开发环境等工具,方便开发者进行C语言的开发和调试工作。 第四,加强技术交流和共享。建立C语言开发者的交流平台,促进经验和知识的共享。通过技术论坛、博客等方式,让开发者能够互相交流和学习,从而提高C语言的编程水平。 综上所述,要彻底解决C语言中的问题,我们需要加强教育培训、加强代码规范和质量管理、提供更好的开发工具和环境,并加强技术交流和共享。这样才能够提高C语言的编程水平,从根本上解决C语言中存在的问题。 ### 回答2: 要彻底解决c这个问题,我们需要以下几个步骤: 首先,我们需要全面了解c这个问题的本质和原因。只有了解问题的根源,我们才能找到解决方案。我们可以通过调查研究、数据分析等方式,深入剖析c出现的原因,找出导致c问题的各种因素。 其次,我们需要制定有针对性的解决策略。针对不同的c问题,我们可以采取不同的解决方案。比如,如果c问题是由于管理不善导致的,我们可以加强管理培训,提高管理水平;如果是由于工艺不合理导致的,我们可以优化工艺流程,提高生产效率。 接着,我们需要实施解决方案,并进行监控和评估。解决方案的实施是解决c问题的关键步骤,我们需要确保每一项方案都能够有效地解决c问题,并能够持续产生效果。同,通过对解决方案进行监控和评估,我们可以及调整和改进方案,以确保解决c问题的效果。 最后,我们需要建立长效机制,预防c问题的再次发生。不仅要解决当前的c问题,还要从根本上避免c问题的再次出现。我们可以建立健全的质量管理体系,加强内部培训和教育,提高员工的质量意识和责任意识。同,定期进行质量检查和评估,及发现和解决潜在的c问题。 总的来说,要彻底解决c这个问题,我们需要全面了解问题的本质和原因,制定有针对性的解决方案,实施并监控方案的执行效果,并建立长效机制预防c问题的再次发生。只有经过这一系列的努力,我们才能够真正解决c问题,提高工作效率和产品质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值