4.2.2初始化串行口
1)DCB设置
串行口打开成功后,接着要对串行口初始化,设置串行口的通信参数。修改这些参数将要用到设备控制块DCB(Device Control Block)。DCB结构定义了串口设备的控制设置,它是个复杂的数据结构,有近30个数据成员。许多通信的重要设置诸如波特率、奇偶校验类型、数据位、停止位等都是在DCB结构中设置的,并能通过DCB随时进行修改。
DCB dcb; //定义数据控制块结构 GetCommState (COMDEV( npTTYInfo ),&dcb); //读串口原来的参数据设置 dcb.BaudRate=9600; dcb.ByreSize=8; dcb.Parity=NOPARITY ; dcb.StopBits=ONESTOPBIT ; SetCommState(COMDEV( npTTYInfo ) ,&dcb); //串口参数设置 |
2)流控设置
①硬件流控
串口通信的硬件流控有两种:DTE/DSR方式和RTS/CTS方式,这与DCB结构的初始化有关系。本程序对这两种方式都进行了处理,使用者可以根据自己的需要任意选择。
bSet = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_DTRDSR) != 0) ; dcb.fOutxDsrFlow = bSet ; if (bSet) dcb.fDtrControl = DTR_CONTROL_HANDSHAKE ; else dcb.fDtrControl = DTR_CONTROL_ENABLE ; bSet = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_RTSCTS) != 0) ; dcb.fOutxCtsFlow = bSet ; if (bSet) dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ; else dcb.fRtsControl = RTS_CONTROL_ENABLE ; |
②软件流控
串口通信中采用特殊字符XON和XOFF控制串口数据的收发。它也是通过对DCB的初始化来完成的,与此相关的DCB成员是:fOutX、fInX、XoffChar、XonChar、XoffLim和XonLim。
bSet = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_XONXOFF) != 0) ; dcb.fInX = dcb.fOutX = bSet ; dcb.XonChar = ASCII_XON ; dcb.XoffChar = ASCII_XOFF ; dcb.XonLim = 100 ; dcb.XoffLim = 100 ; fRetVal = SetCommState( COMDEV( npTTYInfo ), &dcb ) ; return ( fRetVal ) ; |
4.2.3超时设置
在通信中,超时是个很重要的因素。譬如由于某种原因数据接收过程突然被中断或者数据发送过程突然被停止,这时如果不采取相应的措施,可能会引起输入输出线程挂起或被无限阻塞。Windows对于这类问题提供了超时控制机制,通过超时设置来决定通信是否异常并做出相应处理。
串口通信中的超时设置分为两步:首先设置COMMTIMEOUTS结构的五个变量,然后调用SetCommTimeouts()设置超时值。对于使用异步方式读写的操作,如果操作被挂起后,异步成功完成了读写,GetOverlappedResult()函数将返回TRUE。另外还可以用GetCommTimeouts()得到系统的初始值。
4.2.4串行口读写操作
串口的读写操作有两种方式:同步方式(Nonoverlapped)和异步方式(Overlapped)。同步方式是指必须完成了读写操作,函数才返回,这可能造成程序的死掉。因为如果在读写时发生了错误,永远不返回就会出错,可能线程就永远等待在那儿。而异步方式则灵活得多了。当调用CreateFile()函数打开端口时,就会使用FILE-FLAG-OVERLAPPED标志通知o/s(读写完成标志):将在重叠的格式下使用文件。这种情况意味着对ReadFile()函数和WriteFile()函数调用后立即返回,无需等待它们的操作完成。这时ReadFile()函数和WriteFile()函数使用OVERLAPPED管理重叠输入/输出,把这个结构传递给函数,直到异步输入/输出完成才会释放它,之后再把同一结构传递给GetOverlappedReult()函数,以获得最后的输入/输出操作的数据。一旦读写不成功,就将读写挂起,函数直接返回,可以通过GetLastError()函数得知读写未成功的原因。所以,本程序采用异步方式操作:
fReadStat = ReadFile( COMDEV( npTTYInfo ), lpszBlock, dwLength, &dwLength, &READ_OS( npTTYInfo ) ) ; if (!fReadStat) { if (GetLastError() == ERROR_IO_PENDING) { while(!GetOverlappedResult( COMDEV( npTTYInfo ), &READ_OS( npTTYInfo ), &dwLength, TRUE )) { dwError = GetLastError(); if(dwError == ERROR_IO_INCOMPLETE) continue; //读写未完成,继续 else { ClearCommError( COMDEV( npTTYInfo ), &dwErrorFlags, &ComStat ) ; //发生错误,清除错误标志 break; } }}} |
4.2.5关闭串口
串行口是非共享资源,应用程序打开串口后,即独占资源,其它应用程序无法再访问,直到该应用程序释放串口。所以打开串口后,一定要关闭串口。关闭串口只要使用API调用CloseHandle()关闭串口的句柄就可以了。但是值得注意的是在关闭串口之前必须保证读写线程已经退出,在线程退出之前,通知主线程可以关闭串口。
|