串口通信CSerialPort类WriteToPort不能连续发送的问题

转载 2011年11月14日 12:07:18

转载于:http://hi.baidu.com/gilbertjuly/blog/item/e0c035450ec6c845500ffe5a.html

 

RS232串口通信原理详解见:hi.baidu.com/gilbertjuly/blog/item/902a3f11d4b42b0b203f2e39.html

Gilbert在串口通信中使用CSerialPort时,发现连续发送有问题,比如,连续发了三个数组:

m_serial.WriteToPort(chSend1);
m_serial.WriteToPort(chSend2);
m_serial.WriteToPort(chSend2);
//chSend1,chSend2,chSend3是数组首地址.

只有最后一个数组发送成功,开始以为这个类不能连续发送数据,但是后来发现如果写成这个样子:

m_serial.WriteToPort(chSend1);
AfxMessageBox("");
m_serial.WriteToPort(chSend2);
AfxMessageBox("");
m_serial.WriteToPort(chSend3);
AfxMessageBox("");

三个数组的数据就都能发出去,这是为什么呢?

=========================================
这个要看CSerialPort是怎么做出来的,也就是从Windows的串口编程说起。在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序简单,但是控件只能在对话框中使用。其二是调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。CSerialPort类就是对串口的API函数封装。

与以往DOS下串行通信程序不同的是,Windows不提倡应用程序直接控制硬件,而是通过Windows操作系统提供的设备驱动程序来进行数据传递。串行口在Win 32中是作为文件来进行处理的,而不是直接对端口进行操作,对于串行通信,Win 32 提供了相应的文件I/O函数与通信函数,通过了解这些函数的使用,可以编制出符合不同需要的通信程序。

由于是作为文件来处理,我们看看windows API中打开串口的函数:
HANDLE CreateFile( LPCTSTR lpFileName, //将要打开的串口逻辑名,如“COM1”;
DWORD dwDesiredAccess, //指定串口访问的类型,可以是读取、写入或二者并列;
DWORD dwShareMode, //指定共享属性,由于串口不能共享,该参数必须置为0;
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //引用安全性属性结构,缺省值为NULL;
DWORD dwCreationDistribution, //创建标志,对串口操作该参数必须置为OPEN_EXISTING;
DWORD dwFlagsAndAttributes, //属性描述,用于指定该串口进行异步或同步操作;
HANDLE hTemplateFile); //对串口而言该参数必须置为NULL;

=========================================
请务必注意倒数第二个参数dwFlagsAndAttributes,它指示了串口进行异步或同步操作。还请注意这里的同步和异步不是指的数据通信里时钟的同步和异步。这里的同步和异步指的是:

同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程);而异步(重叠)操作方式,API函数会立即返回,操作在后台进行,避免线程的阻塞。

dwFlagsAndAttributes该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作。

既然CSerialPort类是对API函数的封装,我们有理由相信在它的实现里面必定有CreateFile函数,打开它的cpp来看,果然可以搜索的到,再看看它是怎么设置的:

m_hComm = CreateFile(szPort,       // communication port string (COMX)
GENERIC_READ | GENERIC_WRITE,    // read/write types
0,                                // comm devices must be opened with exclusive access
NULL,                            // no security attributes
OPEN_EXISTING,                    // comm devices must use OPEN_EXISTING
FILE_FLAG_OVERLAPPED,      // Async I/O
0);                            // template must be 0 for comm devices

可以看到倒数第二个参数设为FILE_FLAG_OVERLAPPED,即异步发送。

=========================================
其实问题就在这里,异步发送的话就造成文章一开始说的两个现象。

先说第一个现象:为什么三个数组中只发送了最后一个数组?
因为采用了异步操作,在执行到m_serial.WriteToPort(chSend1); 时,并不马上发送串口数据,而是要等进入CSerialPort的线程之后再发送(如果是同步操作,则程序停在那里等发送完成)。
你可以跟踪一下程序,看是什么时候进入它的线程的,三句WriteToPort都会进入这一个线程,而不是三个线程,在这个线程中只发送一次数据,数据的来源就是形参最后的更新,所以就是第三个数组了。

第二个现象:为什么加了AfxMessageBox(""); 就都可以发送?
因为AfxMessageBox(""); 使程序的进程被挂起,这样CSerialPort的线程就得以运行,所以就发送了。

=========================================
看到这里你可能会想:那能不能将dwFlagsAndAttributes改成0设为同步发送?
答案是好像不可以,可能还需要改其他地方,光这里改成同步的话,串口什么数据也发不了。
如果你发现能简易的将这个类改成同步的方法,欢迎联系我caodesheng.1986@yahoo.com.cn

=========================================
那我们要同步发送怎么办?
1.将chSend1,chSend2,chSend3放在一起组建成一个更大的数组一次发送
这样如果接收端处理串口数据较慢的话,可能要在每个数组当中插入些无用的数据。
2.使用其他具有同步操作功能的类,如:
blog.chinaunix.net/u/32550/showart_365425.html
3.学习windows api的同学们还可以自己写串口编程的程序,可以参考:
http://www.vckbase.com/document/viewdoc/?id=1734#%E8%AF%BB%E5%86%99%E4%B8%B2%E5%8F%A3

【解决CSerialPort 串口类不能连续发送的问题】

前面问题是网上找的一个,如下: 我给一个机器发送串口命令,单个命令发送没问题, 连续发送的时候有问题,  比如,连续发了三个,如下: m_ser.WriteToPort(chSend1); m_ser...
  • bigtree_mfc
  • bigtree_mfc
  • 2015年03月24日 10:31
  • 1042

CSerialPort串口类的修正版2014-01-10

这是一份优秀的类文件,好多的地方值得我们学习,具体在多线程,事件,自定义消息,类的封装方面等等。 Remon提供的串口类网址为: http://codeguru.earthweb.com/networ...
  • itas109
  • itas109
  • 2014年01月16日 15:21
  • 4329

CserialPort类函数解析及基本操作流程 基于C++

CserialPort类支持线连接(非MODEM)的串口编程操作。 CserialPort类是基于多线程的,其工作流程如下:首先设置好串口参数,再开启串口检测工作线程,串口检测工...
  • fengqing_123
  • fengqing_123
  • 2015年03月10日 22:24
  • 1362

CSerialPort串口类最新修正版2017-03-12

如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033最新进展:CSerialPort串口类最新修正版2017-12-16http://blo...
  • itas109
  • itas109
  • 2016年05月07日 13:59
  • 7489

CSerialPort的WriteToPort 连续发送的问题分析

http://blog.sina.com.cn/s/blog_6b94d56801012stv.html CSerialPort的WriteToPort 连续发送的问题分析 G...
  • robinson_911
  • robinson_911
  • 2014年04月10日 22:58
  • 579

结合CSerialPort类,实现完整的串口收发功能

最近的的项目软件,需要增加串口的收发,因需要统一到同一个通讯通讯框架,(之前已有USB,读卡器等)从API上看,我最希望其能简化成如下的简洁形式:   bool UartRcvData(LPCBYT...
  • anribras
  • anribras
  • 2016年12月05日 10:05
  • 1103

CSerialPort不能连续发送的问题

1.void CSerialPort::WriteChar(CSerialPort* port) { BOOL bWrite = TRUE; BOOL bResult = TRUE; DWOR...
  • xufan123123
  • xufan123123
  • 2013年08月30日 18:44
  • 2442

C++编程->基于CSerialPort类的串口通信测试

先写一段单片机的代码,用于上位机测试。 void setup() { Serial.begin(9600); // opensserial port, sets data rate to 960...
  • sunboyiris
  • sunboyiris
  • 2017年08月04日 16:02
  • 381

用CSerialPort类收不到0x11, 0x13问题及解决办法

在VS2010平台下编写modbusRTU程序,在调试的时候发现CSerialPort串口类无法接收到0x11, 0x13,随后百度找的一篇Linux下的文章,大受启发,原文如下: linux串口...
  • xiaojiaohuazi
  • xiaojiaohuazi
  • 2013年07月09日 15:40
  • 1652

基于CSerialPort修改类的串口调试助手源代码(支持中文、自动保存等)

如需转载请标明出处:http://blog.csdn.net/itas109     本串口工具集成目前多数串口工具的优秀功能于一身,采用CSerialPort类进行编写,并在此基础上对该类进行了改...
  • itas109
  • itas109
  • 2014年01月16日 15:35
  • 4124
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:串口通信CSerialPort类WriteToPort不能连续发送的问题
举报原因:
原因补充:

(最多只允许输入30个字)