转到上位机做开发 VC还是有些东西不太一样 绕了些圈子 在此做一下记录 对一些基本概念做一些说明
项目中要求有多个串口的转发通信 不定时、随机长度帧的帧处理转发等操作
1.初始化及其中涉及到的问题
HCom1ConnWithLcd = CreateFile("COM1",//COM1 GENERIC_READ|GENERIC_WRITE, //允许读和写 0, //独占方式 NULL, OPEN_EXISTING, //打开而不是创建 //FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL); if(HCom1ConnWithLcd == INVALID_HANDLE_VALUE) return false; SetupComm(HCom1ConnWithLcd,SYS_COM_BUF_LEN,SYS_COM_BUF_LEN);//输入输出缓冲区大小设置 PurgeComm(HCom1ConnWithLcd,PURGE_TXCLEAR|PURGE_RXCLEAR);//清除串口缓冲区 COMMTIMEOUTS TimeOuts; //设定读超时----------------------------------------------------------------------------- TimeOuts.ReadIntervalTimeout=0; TimeOuts.ReadTotalTimeoutMultiplier=0; TimeOuts.ReadTotalTimeoutConstant=0; //在读一次输入缓冲区的内容后读操作就立即返回//而不管是否读入了要求的字符。 //设定写超时 TimeOuts.WriteTotalTimeoutMultiplier=100; TimeOuts.WriteTotalTimeoutConstant=500; SetCommTimeouts(HCom1ConnWithLcd,&TimeOuts); //设置超时--------------------------------------------------------- DCB dcb; GetCommState(HCom1ConnWithLcd,&dcb); dcb.BaudRate=115200; //波特率为115200bps dcb.ByteSize=8; //每个字节有8位 dcb.Parity=NOPARITY; //无奇偶校验位 dcb.StopBits=ONESTOPBIT; //1个停止位 SetCommState(HCom1ConnWithLcd,&dcb); return TRUE;
上述代码很常见,但标红的两个点在后续调试的时候困扰了好一会
问题1.关于串口的重叠模式和同步模式
第一次写的时候将串口都声明成了同步模式,然后
SetCommMask(HCom2 , EV_RXCHAR );
每次接收一字节,理论上这样无论帧的长度、发送间隔 怎样变化对上位机来说都没有问题。
但调试时发现无法发送数据,DEBUG跟踪发现,到writefile()函数直接阻塞了,原来是设置成同步模式后调用
WaitCommEvent(HCom2, &dwCommEvent, &m_osReadEx);
因为上面已经设置了 EV_RXCHAR,接收进程WaitCommEvent()函数会一直阻塞句柄,导致写函数无法取得句柄阻塞跳出
于是又重新改写结构将串口声明成异步的 即声明添加 FILE_FLAG_OVERLAPPED, //重叠方式
重叠方式与同步方式的区别就是重叠方式执行发送或写入操作后函数就退出并不阻塞,而同步方式阻塞函数等待IO操作完成
反应在代码上异步会以如下一种形式体现:
bReadStu = Readfile(hanle,lp,读取缓存指针,读取字节数,&读取字节数,OVERLAPPED) if(!bReadStu ){ if(bReadStu ==IO_PENDING) WaitforSingalObject(hEvent , INFINITE ); }
其中hEvent为 OVERLAPPED结构体中的变量由Readfile函数赋值代表IO操作完成
读取字节数,&读取字节数 输入数据的同时又输入引用时因为函数要在操作后清零"读取字节数"变量
这里就是如果不用WaitforSingalObject阻塞,代码继续执行,这就是异步
注意Readfile()函数并不一定要IO_PENDING 也可以直接读取成功返回一个非零值的读取字节数
问题2:为什么接收数据不完整
声明为异步模式后读写操作都正常了,但是发现接收的数据总是会丢字节。
因为正确接收后基本会有一个
PurgeComm(HCom2, PURGE_RXABORT|PURGE_RXCLEAR);
操作,来清除缓存,如果一字节一接收一处理,在接收到第一个字节处理结束后PurgeComm,就有可能清除在接收字节过程中接收到的其他字节,如果不清那缓存总有用完的时候,"接收队列溢出"错误就会出现。清就伴随了永远可能丢失下一个字节的问题。
修改了接收模式,近可能让缓存接受到完整的一帧后利用帧的间隔来处理,数据完整性大大提高。但这个问题其实没有解决,在帧数据长度,发送时间随机的情况下无法判断下一帧什么时间到来,什么是一帧的结束。
有人会说帧是有结构的当然可以判断帧的开始结束,问题是缓存不会判断这个,他们只是接收、发送。解析的事情还是在程序里自己做的。更不要说还会有非正常的数据错误,这会引出要不要使用校验的问题。原本的下位机是没有起用校验的,也没什么问题,但连续长帧在经过几个串口转发后就会出现一定错误率。本例中下位机程序也是我写的,所以可以更容易两边更改来互相迁就。
让帧之间尽量有一个时间间隔,1ms,2ms的都可以。这样给出时间让帧解析以减少丢数据的发生。
问题3:为什么Readfile()不阻塞
bReadStu = Readfile(hanle,lp,读取缓存指针,读取字节数,&读取字节数,OVERLAPPED)
if(!bReadStu )
{ if(bReadStu ==IO_PENDING)
WaitforSingalObject(hEvent , INFINITE );
}
运行到图示位置无论有没有数据都不阻塞
这是因为超时没有设置好。
TimeOuts.ReadIntervalTimeout=MAXWORDS;
TimeOuts.ReadTotalTimeoutMultiplier=0;
imeOuts.ReadTotalTimeoutConstant=0;
//在读一次输入缓冲区的内容后读操作就立即返回//而不管是否读入了要求的字符。
ReadIntervalTimeout参数是读入一个字节后与下一个字节到来的间隙,如果过了这个间隙就要超时。超时了函数是要返回的,返回就是这个信号量不在pending.
修改ReadIntervalTimeout=0;取消这个间隔判断。
这里有个重要的概念就是各种超时发生时,PENDING操作都会返回
问题4:各种崩溃情况
基本都是0xcxxxxxxx在0x0xxxxxxxx出发生了读写冲突。好好检查数组越界的问题,一般发生错误弹窗的时候会中断下来,就是发生越界的点。看一下调用堆栈,函数局部变量的数据,可以很容发现问题。不行就排除法加大缓存容量。
相关推荐
基于MFC对话框的 WIN32 API串口通信程序
里面包含许多有关于vc win32 api 串口编程方面的有用资料...
使用vs2013写的纯win32 api 串口调试助手
windows API串口开发
[062]深入浅出VC++串口编程之基于Win32 API.zip上位机开发VC串口学习资料源码下载[062]深入浅出VC++串口编程之基于Win32 API.zip上位机开发VC串口学习资料源码下载[062]深入浅出VC++串口编程之基于Win32 API.zip...
深入浅出VC++串口编程之基于Win32 API 源码 参照该文档编写 同步阻塞方式 非常适合初学者 点击发送之后不要移动鼠标,否则会导致无响应,因为是同步方式 仅供学习,下一步我会上传异步通讯方式的,建议大家以后写...
基于 win32 API 串口通讯收发设置等。 文件传送 在线升级 demo,VC2005 编译通过。很强大的说~!
windows下C语言基于WIN32 API的同步方式读PC串口 不使用控件与类,全C实现。包含完整源代码和示例,注释清晰。分scom.h和scom.c文件。
使用Win32API实现Windows下异步串口通讯 目录:1.异步非阻塞串口通讯的优点2.异步非阻塞串口通讯的基本原理3.异步非阻塞串口通讯的基础知识4.异步非阻塞串口通讯的实现步骤一,异步非阻塞串口通讯的优点读写...
WIN32 API串口通讯实例教程,包括串口通讯的函数介绍和举例
WIN32API串口通讯程序
vs2010下WIN32API函数实现的异步mfc窗口串口通信实例,里面有很详细的注释和函数解释,程序流程我也写下来了,对初学串口很有帮助
很好的串口资料
串口可以自己设置,数据位校验位都可以自己更改,
使用Win32API实现Windows下异步串口通讯:目录:1. 异步非阻塞串口通讯的优点2. 异步非阻塞串口通讯的基本原理3. 异步非阻塞串口通讯的基础知识4. 异步非阻塞串口通讯的实现步骤
来源于网络,还原于网络, 简单的串口编程基于API
整理的Windows下串口类,封装了Win32 API,挺实用的,供下载参考
在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序简单,但欠灵活。其二是调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。本文我们只介绍API串口...
一种在Window s 9x 及以上操作系统下利用Win32 API函数实现串行通讯的方法, 引入异步I /O操作及事件驱动机制, 成功地解决了在32位视窗操作系统下计算机监控系统实时串行通讯问题, 并给出了部分串口通讯的源代码。
C#调用API串口通信C# calls API serial communication