使用Win32API实现Windows下异步串口通讯目录:1.异步非阻塞串口通讯的优点2.异步非阻塞串口通讯的基本原理3.异步非阻塞串口通讯的基础知识4.异步非阻塞串口通讯的实现步骤一,异步非阻塞串口通讯的优点读写串行口时,既可以同步执行,也可以重叠(异步)执行。在同步执行时,函数直到操作完成后才返回。这意味着在同步执行时线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,调用的函数也会立即返回。费时的I/O操作在后台进行,这样线程就可以干别的事情。例如,线程可以在不同的句柄上同时执行I/O操作,甚至可以在同一句柄上同时进行读写操作。重叠一词的含义就在于此。二,异步非阻塞串口通讯的基本原理首先,确定要打开的串口名、波特率、奇偶校验方式、数据位、停止位,传递给CreateFile()函数打开特定串口;其次,为了保护系统对串口的初始设置,调用GetCommTimeouts()得到串口的原始超时设置;然后,初始化DCB对象,调用SetCommState()设置DCB,调用SetCommTimeouts()设置串口超时控制;再次,调用SetupComm()设置串口接收发送数据的缓冲区大小,串口的设置就基本完成,之后就可以启动读写线程了。三,异步非阻塞串口通讯的基础知识下面来介绍并举例说明一下编写异步非阻塞串口通讯的程序中将会使用到的几个关键函数CreateFile()功能:打开串口设备函数原型HANDLECreateFile(LPCTSTRlpFileName,//串口名称字符串;如:COM1或COM2DWORDdwDesiredAccess,//设置读写属性(访问模式);一般为GENERIC_READ|GENERIC_WRITE,DWORDdwShareMode,//共享模式;必须为0,即不能共享LPSECURITY_ATTRIBUTESlpSecurityAttributes,//安全属性;一般为NULLDWORDdwCreationDistribution,//创建方式,串口设置必须设置此值;在这里必须为OPEN_EXISTINGDWORDdwFlagsAndAttributes,//文件属性和标志;在这里我们设置成FILE_FLAG_OVERLAPPED,实现异步I/OHANDLEhTemplateFile//临时文件的句柄,通常为NULL);说明:如果调用成功,那么该函数返回文件的句柄,如果调用失败,则函数返回INVALID_HANDLE_VALUE。Forexample:Handlem_hComm=CreateFile(com1,GENERIC_READ||GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);CloseHandle();功能:关闭串口BOOLCloseHandle(HANDLEhObject//handletoobjecttoclose)这个,我想就不多说了吧!GetCommState()功能:获得串口状态BOOLGetCommState(HANDLEhFile,//handleofcommunicationsdeviceLPDCBlpDCB//addressofdevice-controlblockstructure);SetCommState()功能:设置串口状态BOOLSetCommState(HANDLEhFile,//handleofcommunicationsdeviceLPDCBlpDCB//addressofdevice-controlblockstructure);说明:在打开通信设备句柄后,常常需要对串行口进行一些初始化工作。这需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、每个字符的数据位数、奇偶校验和停止位数等信息。在查询或配置置串行口的属性时,都要用DCB结构来作为缓冲区。调用GetCommState函数可以获得串口的配置,该函数把当前配置填充到一个DCB结构中。一般在用CreateFile打开串行口后,可以调用GetCommState函数来获取串行口的初始配置。要修改串行口的配置,应该先修改DCB结构,然后再调用SetCommState函数用指定的DCB结构来设置串行口Forexample:DCBdcb;memset(&dec,0,dizeof(dcb));if(!GetCommState(HComm,&dcb))//获取当前DCB配置returnFALSE;dcb.BaudRate=CBR_9600;//修改数据传输率............if(SetCommState(hComm,&dcb))//设置新参数......//错误处理BuildCommDCB()功能:初始化DCB结构BOOLBuildCommDCB(LPCTSTRlpDef,//pointertodevice-controlstringLPDCBlpDCB//pointertodevice-controlblock);Forexample:DCBdcb;memset(&dcb,0,sizeof(dcb));dcb.DCBlength=sizeof(dcb);if(!BuildCommDCb(9600,n,8,1,&dcb))//baud=9600parity=Ndata=8stop=1{......//参数修改错误returnFALSE;}else{......//己准备就绪}说明:功能同上面的例子。SetupComm()功能:设置I/O缓冲区的大小函数原型:BOOLSetupComm(HANDLEhFile,//handletocommunicationsdeviceDWORDdwInQueue,//sizeofinputbufferDWORDdwOutQueue//sizeofoutputbuffer);说明:除了在DCB中的设置外,程序一般还需要设置I/O缓冲区的大小和超时。Windows用I/O缓冲区来暂存串行口输入和输出的数据,如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。先介绍一个结构:COMMTIMEOUTStypedefstruct_COMMTIMEOUTS{DWORDReadIntervalTimeout;//读间隔超时DWORDReadTotalTimeoutMultiplier;//读时间系数DWORDReadTotalTimeoutConstant;//读时间常量DWORDWriteTotalTimeoutMultiplier;//写时间系数DWORDWriteTotalTimeoutConstant;//写时间常量}COMMTIMEOUTS,*LPCOMMTIMEOUTS;再介绍两个函数GetCommTimeouts功能:读取TimeOut的值函数原型:BOOLGetCommTimeouts(HANDLEhFile,//handleofcommunicationsdeviceLPCOMMTIMEOUTSlpCommTimeouts//addressofcomm.time-outsstructure);SetCommTimeouts功能:设置TimeOUt的值函数原型:BOOLSetCommTimeouts(HANDLEhFile,//handleofcommunicationsdeviceLPCOMMTIMEOUTSlpCommTimeouts//addressofcommunicationstime-outstructure);这里顺便介绍一下TimeOut机制的两个性质:超时函数说明:在用ReadFile和WriteFile读写串行口时,需要考虑超时问题。如果在指定的时间内没有读出或写入指定数量的字符,那么ReadFile或WriteFile的操作就会结束。要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。调用SetCommTimeouts可以用某一个COMMTIMEOUTS结构的内容来设置超时。有两种超时:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延,总超时是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。用COMMTIMEOUTS结构可以规定读/写操作的超时,该结构的定义为:COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是:总超时=时间系数×要求读/写的字符数+时间常量例如,如果要读入10个字符,那么读操作的总超时的计算公式为:读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant可以看出,间隔超时和总超时的设置是不相关的,这可以方便通信程序灵活地设置各种超时。如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时,如果ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都为0,则不使用读总超时。如果读间隔超时被设置成MAXDWORD并且两个读总超时为0,那么在读一次输入缓冲区中的内容后读操作就立即完成,而不管是否读入了要求的字符。在用重叠方式读写串行口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile和WriteFile的返回时间。Forexample:COMMTIMEOUTStimeOver;memset(&&timeOver.0.sizeof(timeOver));DWORDtimeMultiplier,timeConstant;timeOver.ReadTotalTimeoutMultiplier=timeMultiplier;timeOver.ReadTotalTimeoutConstant=timeConstant;SetCommTimeouts(hComport,&&timeOver);ReadFile()功能:读取数据函数原型:BOOLReadFile(HANDLEhFile,//串口名称字符串(文件句柄)LPVOIDlpBuffer,//读缓冲区DWORDnNumberOfBytesToRead,//要求读入的字节数LPDWORDlpNumberOfBytesRead,//实际读入的字节数LPOVERLAPPEDlpOverlapped//指向一个OVERLAPPED结构);//若返回TRUE则表明操作成功Forexample:char*pReciveBuf;DWORDnWantRead=100,nReadRead;LPOVERLAPPEDm_OverlappedRead;BOOLbReadStatus=ReadFile(m_hComm,preciveBuf,nWantRead,&&nReadRead,&&m_OverlappedRead);WriteFile()功能:来将资料写入Serialport.函数原型:BOOLWriteFile(HANDLEhFile,//handletofiletowritetoLPCVOIDlpBuffer,//pointertodatatowritetofileDWORDnNumberOfBytesToWrite,//numberofbytestowriteLPDWORDlpNumberOfBytesWritten,//pointertonumberofbyteswrittenLPOVERLAPPEDlpOverlapped//pointertostructureneededforoverlappedI/O);说明:ReadFile函数只要在串行口输入缓冲区中读入指定数量的字符,就算完成操作。而WriteFile函数不但要把指定数量的字符拷入到输出缓冲中,而且要等这