·打开串口: HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); 在Windows CE下,利用CreateFile函数打开一个COM口时,dwShareMode(共享模式)必须设置为0,表示独占方式;lpSecurityAttributes(安全参数)必须设置为NULL;hTemplateFile(模板文件)必须设置为NULL;dwCreationDisposition需要设置为OPEN_EXISTING。则上述函数简化为: HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, 0, NULL, OPEN_EXISTING, DWORD dwFlagsAndAttributes, NULL ); 其中dwDesiredAccess设置为GENERIC_READ表示可读,设置为GENERIC_WRITE表示可写。通常可通过如下示例打开一个串口。 CreateFile( _T("COM1:"), GENERIC_READ | GENERIC_WRITE, //允许读和写 0, //独占方式(共享模式) NULL, OPEN_EXISTING, //打开而不是创建(创建方式) 0, NULL ); 打开串口成功,函数返回串口句柄;打开串口失败,函数返回INVALID_HANDLE_VALUE ·关闭串口: BOOL CloseHandle( HANDLE hObject ); 如:CloseHandle(m_hComm); //m_hComm是CreateFile函数返回的串口句柄。 关闭串口成功,函数返回非零值;关闭串口失败,函数返回零。 ·DCB(设备控制块): DCB结构完全描述了串口的使用参数。 typedef struct _DCB { DWORD DCBlength; /* sizeof(DCB) */ DWORD BaudRate; /* Baudrate at which running */ DWORD fBinary: 1; /* Binary Mode (skip EOF check) */ DWORD fParity: 1; /* Enable parity checking */ DWORD fOutxCtsFlow:1; /* CTS handshaking on output */ DWORD fOutxDsrFlow:1; /* DSR handshaking on output */ DWORD fDtrControl:2; /* DTR Flow control */ DWORD fDsrSensitivity:1; /* DSR Sensitivity */ DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */ DWORD fOutX: 1; /* Enable output X-ON/X-OFF */ DWORD fInX: 1; /* Enable input X-ON/X-OFF */ DWORD fErrorChar: 1; /* Enable Err Replacement */ DWORD fNull: 1; /* Enable Null stripping */ DWORD fRtsControl:2; /* Rts Flow control */ DWORD fAbortOnError:1; /* Abort all reads and writes on Error */ DWORD fDummy2:17; /* Reserved */ WORD wReserved; /* Not currently used */ WORD XonLim; /* Transmit X-ON threshold */ WORD XoffLim; /* Transmit X-OFF threshold */ BYTE ByteSize; /* Number of bits/byte, 4-8 */ BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */ BYTE StopBits; /* 0,1,2 = 1, 1.5, 2 */ char XonChar; /* Tx and Rx X-ON character */ char XoffChar; /* Tx and Rx X-OFF character */ char ErrorChar; /* Error replacement char */ char EofChar; /* End of Input character */ char EvtChar; /* Received Event character */ WORD wReserved1; /* Fill for now. */ } DCB, *LPDCB; DCBlength:指定DCB结构的大小。 BaudRate:指定通信设备的波特率,常用的如:CBR_9600。 fBinary:该参数必须设置为TRUE,使能二进制传输模式,因为Win32 API不支持非二进制传输模式。 fParity:指定是否执行奇偶校验。 fOutxCtsFlow:指定CTS(clear-to-send)信号是否被监视并作为输出流控制信号。如果该参数设置为TRUE,同时CTS信号被关闭,则输出被挂起,直到CTS信号重新发出。 fOutxDsrFlow:指定DSR(data-set-ready)信号是否被监视并作为输出流控制信号。如果该参数设置为TRUE,同时DSR信号被关闭,则输出被挂起,直到DSR信号重新发出。 fDtrControl:指定DTR(data-terminal-ready)信号是否作为数据流控制信号。该参数可以设置为: | 当串口设备打开时,DTR信号线始终设为禁止 | DTR_CONTROL_ENABLE | 当串口设备打开时,DTR信号线设为使能并始终打开 | DTR_CONTROL_HANDSHAKE | 使DTR支持握手,此时可以调用EscapeCommFunction函数来释放DTR线上的错误 | | |
fDsrSensitivity:指定串口通信设备是否对DSR信号状态敏感。设置为TRUE,则除非DSR信号线上的电平为高,否则接收到的字节将被忽略。 fTXContinueOnXoff:指定当输入缓冲区满且收到XoffChar字符时,传输是否终止。该参数设置为TRUE,则输入缓冲区的字节数小于XoffLim定义的字节数时传输将继续,发送完XoffChar字节后将停止接收字节。如果该参数设置为FALSE,那么只有当输入缓冲区的字节数在XonLim定义的字节数内,且驱动程序发送过XonChar字符以恢复接收过程时,传输才会继续。 fOutX:指定在数据发送期间是否使用XON/XOFF流控制。该参数设置为TRUE,则当接收到XoffChar字符时将停止发送,直到接收到XonChar字符时开始发送。 fInX:指定在接收数据期间是否使用XON/XOFF流控制。该参数设置为TRUE,则当输入缓冲区中存有数据的空间达到XoffLim定义的字节数时,XoffChar将被发送;当输入缓冲区中可用的空间达到XonLim定义的字节数时,XonChar被发送。 fErrorChar:指定当收到的字符发生奇偶校验错误时,是否使用ErrorChar成员定义的字符代替。该参数设置为TRUE,且fParity设置为TRUE,将会发生替换。 fNull:指定null是否被丢弃,设置为TRUE,则接收到的null字符被丢弃。 fRtsControl:指定RTS(request-to-send)流控制,若该参数为0,则缺省值为RTS_CONTROL_HANDSHAKE。 RTS_CONTROL_DISABLE | 当串口设备打开时,RTS线始终为禁止 | RTS_CONTROL_ENABLE | 当设备打开时,RTS线始终设为使能并始终打开 | RTS_CONTROL_HANDSHAKE | 启动RTS握手功能。当输入缓冲区字符小于缓冲区总数的1/2时,驱动程序使RTS信号为高,超过3/4时,使RTS信号为低。若RTS握手功能可用,可调用EscapeCommFunction函数释放DTR线上的错误 | RTS_CONTROL_TOGGLE | 指定当发送数据时,RTS信号线为高,缓冲区数据发送完,RTS信号线为低 | | |
fAbortOnError:指定当错误发生时,读写操作是否终止。该参数设置为TRUE,则当错误发生时,所有的读写操作将终止。直到应用程序调用ClearCommError函数来获取错误信息之后,驱动程序才会进行进一步的通信。 fDummy2:该参数保留,未用。 wReserved:该参数没有被使用,必须设置为0。 XonLim:指定发送XON字符前输入缓冲区允许的最小字节数。 XoffLim:指定发送XOFF字符前输入缓冲区允许的最大字节数。最大允许接收字符数可以用定义的全部输入缓冲区字节数减去此值得到。 ByteSize:指定一个传送字节中的数据位数(数据位)。 Parity:指定奇偶校验方法 EVENPARITY | 偶校验 | MARKPARITY | 标记校验 | NOPARITY | 无校验 | ODDPARITY | 奇校验 | SPACEPARITY | Space | | |
StopBits:指定停止位的位数 ONESTOPBIT | 1位停止位 | ONE5STOPBITS | 1.5位停止位 | TWOSTOPBITS | 2位停止位 | | |
XonChar:指定发送接收的XON字符。 XoffChar:指定发送接收的XOFF字符。 ErrorChar:指定当接收到的数据发生奇偶校验错误时替换的字符。 EofChar:指定某字符作为数据结束标记。 EvtChar:指定某字符作为事件标记。 wReserved1:该参数保留,未用。 ·配置串口: BOOL GetCommState( HANDLE hFile, LPDCB lpDCB ); 该函数用来获取已打开串口的参数信息,并将这些信息填充到lpDCB参数所指向的DCB(设备控制块)中。 返回值:成功返回非零值,失败返回零 BOOL SetCommState( HANDLE hFile, LPDCB lpDCB ); 返回值:成功返回非零值,失败返回零 该函数用来设置已打开串口的参数信息。 在设置串口参数时,一般先调用GetCommState函数获取串口参数信息到一个DCB(设备控制块)中,然后对感兴趣的参数进行修改,最后再调用SetCommState函数完成串口参数的配置。 例如可以通过如下代码配置串口参数: —————————————————————————————————— //得到打开串口的当前属性参数,修改后再重新设置串口。 if (!GetCommState(m_hComm,&DCB_COM1)) { TRACE(_T("GetCommState error")); return FALSE; } //设置串口参数 DCB_COM1.BaudRate = CBR_9600; // 设置波特率9600 DCB_COM1.fBinary = TRUE; // 设置二进制模式,此处必须设置TRUE DCB_COM1.fParity = TRUE; // 支持奇偶校验 DCB_COM1.fOutxCtsFlow = FALSE; // No CTS output flow control DCB_COM1.fOutxDsrFlow = FALSE; // No DSR output flow control DCB_COM1.fDtrControl = DTR_CONTROL_DISABLE; // No DTR flow control DCB_COM1.fDsrSensitivity = FALSE; // DSR sensitivity DCB_COM1.fTXContinueOnXoff = TRUE; // XOFF continues Tx DCB_COM1.fOutX = FALSE; // No XON/XOFF out flow control DCB_COM1.fInX = FALSE; // No XON/XOFF in flow control DCB_COM1.fErrorChar = FALSE; // Disable error replacement DCB_COM1.fNull = FALSE; // Disable null stripping DCB_COM1.fRtsControl = RTS_CONTROL_DISABLE; //No RTS flow control DCB_COM1.fAbortOnError = FALSE; // 当串口发生错误,并不终止串口读写 DCB_COM1.ByteSize = 8; // 数据位,范围:4-8 DCB_COM1.Parity = NOPARITY; // 校验模式 DCB_COM1.StopBits = 0; // 1位停止位 //设置串口参数 if (!SetCommState(m_hComm, &DCB_COM1)) { TRACE(_T("SetCommState error")); return FALSE; } —————————————————————————————————— ·读写串口: BOOL ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ); hFile:CreateFile函数返回的串口句柄。 lpBuffer:指定接收数据的缓冲区。 nNumberOfBytesToRead:想要读取的字节数。 lpNumberOfBytesRead:实际读取的字节数。 lpOverlapped:Windows CE不支持,设置为NULL。 BOOL WriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ); hFile:CreateFile函数返回的串口句柄。 lpBuffer:指定存储发送数据的缓冲区。 nNumberOfBytesToRead:指定将要发送的数据的字节数。 lpNumberOfBytesRead:实际发送的数据的字节数。 lpOverlapped:Windows CE不支持,设置为NULL。 读写函数的返回值都是成功时返回非零值,失败时返回零。 例: DWORD dwLength; char *recvBuf = new char[1024]; BOOL fReadState = ReadFile(m_hComm, recvBuf, 1024, &dwLength, NULL); delete[] recvBuf; DWORD dwactlen; char *psendbuf = new char[32]; BOOL fWriteState = WriteFile(m_hComm, psendbuf, 32, &dwactlen, NULL); delete[] psendbuf; 需要注意的是,由于从串口读写数据的速度比较慢,因此一般情况下,不会在主线程中读写大量的数据,而是创建单独的线程来读写数据,特别是读数据。
·异步串口I/O: BOOL GetCommMask( HANDLE hFile, LPDWORD lpEvtMask ); BOOL SetCommMask( HANDLE hFile, DWORD dwEvtMask ); BOOL WaitCommEvent( HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped ); GetCommMask函数用于得到串口已经设置了的串口事件,参数hFile指定已打开的串口句柄,参数lpEvtMask用于存取得到的串口事件集。SetCommMask函数的功能与GetCommMask函数正好相反,用于设置串口事件集。WaitCommEvent函数用于等待预先设置的串口事件中的某一个事件发生,该函数将阻塞线程,直到预先设置的串口事件中的某一事件的发生。参数lpEvtMask用于存储已经发生的事件,参数lpOverlapped必须设置为NULL,因为在Windows CE中不支持重叠I/O操作。 串口时间表: EV_BREAK | 检测到中断发生 | EV_CTS | CTS信号改变了状态 | EV_DSR | DSR信号改变了状态 | EV_ERR | 串口驱动程序检测到了错误,如CE_RXPARITY,CE_OVERRUN,CE_FRAME | EV_RING | 检测到振铃 | EV_RLSD | RLSD信号改变了状态 | EV_RXCHAR | 接收到了一个字符 | EV_RXFLAG | 接收到了一个事件字符 | EV_TXEMPTY | 在输出缓冲区中的最后一个字符被发送 | | |
·设置端口读写超时: BOOL GetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); BOOL SetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); 在用ReadFile和WriteFile读写串口时,需要考虑超时问题。如果在指定的时间内没有读出或者写入指定数量的字节数据,那么ReadFile函数或者WriteFile函数就会返回。GetCommTimeouts函数用来查询当前的超时时间设置,该函数会填充一个COMMTIMEOUTS结构。SetCommTimeouts函数用来通过一个COMMTIMEOUTS结构设置超时时间。两个函数的返回值都是成功时返回非零值,失败时返回零。 typedef struct _COMMTIMEOUTS { DWORD ReadIntervalTimeout; /*读间隔超时*/ DWORD ReadTotalTimeoutMultiplier; /*读时间系数*/ DWORD ReadTotalTimeoutConstant; /*读时间常量*/ DWORD WriteTotalTimeoutMultiplier; /*写时间系数*/ DWORD WriteTotalTimeoutConstant; /*写时间常量*/ } COMMTIMEOUTS,*LPCOMMTIMEOUTS; ReadIntervalTimeout:以毫秒为单位设置通信线路上的两个字符到达之间最大时间间隔。在ReadFile操作期间,从接收到第一个字符开始计时。如果任意两个字符到达之间的时间间隔超过这个最大值,则ReadFile操作完成,返回缓冲数据。如果该值设置为0,则不使用间隔超时。 ReadTotalTimeoutMultiplier:读时间系数。以毫秒为单位设置一个用来计算读操作总超时时间的时间系数。 ReadTotalTimeoutConstant:读时间常量。以毫秒为单位设置一个用来计算读操作总超时时间的时间常量。 读总超时时间 = 读时间系数*要读的字节数 + 读时间常量 WriteTotalTimeoutMultiplier:写时间系数。以毫秒为单位设置一个用来计算写操作总超时时间的时间系数。 WriteTotalTimeoutConstant:写时间常量。以毫秒为单位设置一个用来计算写操作总超时时间的时间常量。 写总超时时间 = 写时间系数*要写的字节数 + 写时间常量 超时有间隔超时和总超时两种类型。间隔超时是指在接收时两个字符之间的最大时延。从串口读取数据时,当接收到一个字节时,通信驱动程序启动一个内部定时器开始计时,在下一个字节到来之前,如果定时器时间超过了间隔超时时间,读操作就会被放弃。总超时是指读操作或者写操作总共花费的最大时间。写操作只支持总超时,读操作对两种类型的超时都支持。 如果应用程序将ReadIntervalTimeout和ReadTotalTimeoutMultiplier设置为MAXDWORD,并且将ReadTotalTimeoutConstant设置为大于0并且小于MAXDWORD的数,则调用ReadFile函数时,会有以下情况: 1 如果接收缓冲区中有字符存在,则ReadFile函数立即返回这些字符。 2 如果接收缓冲区中没有字符,则ReadFile函数会等待直到一个字符到达,然后立即返回。 3 若在ReadTotalTimeoutConstant设定的时间内没有任何字符到达,则ReadFile超时返回。 间隔超时和总超时的设置是不相关的。 下面列举一些情况: 1 有读间隔超时,读总超时,写总超时:将COMMTIMEOUTS结构中的五个成员设置为相应值。 2 有读总超时,写总超时:将ReadIntervalTimeout设置为0,将其他成员设置为相应值。 3 在读一次输入缓冲区中的内容后,读操作就立即完成,不管是否读入了要求的字符:将ReadIntervalTimeout设置为MAXDWORD, 将ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都设置为0。 4 ReadFile没有超时设置,直到有适当的字符数返回或者错误发生,该函数才返回:将ReadIntervalTimeout,ReadTotalTimeoutMultiplier和 ReadTotalTimeoutConstant都设置为0。 5 WriteFile没有超时设置:将WriteTotalTimeoutMultiplier和 WriteTotalTimeoutConstant都设置为0。 例: —————————————————————————————————— COMMTIMEOUTS CommTimeOuts; GetCommTimeouts(m_hComm, &CommTimeOuts); CommTimeOuts.ReadIntervalTimeout = 100;/* 接收字符间最大时间间隔 */ CommTimeOuts.ReadTotalTimeoutMultiplier = 1; CommTimeOuts.ReadTotalTimeoutConstant = 100;/* 读数据总超时常量 */ CommTimeOuts.WriteTotalTimeoutMultiplier = 0; CommTimeOuts.WriteTotalTimeoutConstant = 0; SetCommTimeouts(m_hComm, &CommTimeOuts); —————————————————————————————————— —————————————————————————————————— COMMTIMEOUTS CommTimeOuts; GetCommTimeouts (m_hComm, &CommTimeOuts); CommTimeOuts.ReadIntervalTimeout = MAXDWORD; CommTimeOuts.ReadTotalTimeoutMultiplier = 0; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 10; CommTimeOuts.WriteTotalTimeoutConstant = 1000; SetCommTimeouts( m_hComm, &CommTimeOuts ) ——————————————————————————————————
·设置接收/发送缓冲区大小: BOOL SetupComm( HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue ); hFile指定已打开的串口句柄,dwInQueue指定接收缓冲区的大小,dwOutQueue指定发送缓冲区的大小。 返回值:成功时返回非零值,失败时返回零。 例: SetupComm(m_hComm,512,512); 如果不使用该函数,系统会推荐一个适合的默认值。 ·控制串口: BOOL SetCommBreak( HANDLE hFile ); BOOL ClearCommBreak( HANDLE hFile ); SetCommBreak函数用来停止串口传输字符并且设置串口为中断状态,ClearCommBreak函数用于重新传输字符,hFile指定已打开的串口句柄。 ·清空串口缓冲区: BOOL PurgeComm( HANDLE hFile, DWORD dwFlags ); PurgeComm函数用于清空串口的接收缓冲区与发送缓冲区。dwFlags参数用来设置操作类型,设置为PURGE_TXCLEAR,表示清空发送缓冲区,设置为PURGE_RXCLEAR,表示清空接收缓冲区。两者也可以组合使用,表示同时清空接收缓冲区和发送缓冲区。 例: PurgeComm(ceSeries->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR ); ·清除错误并查询状态: BOOL ClearCommError( HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat ); ClearCommError函数用于清除驱动程序产生的任何错误并返回当前串口的状态。lpErrors表示发生的错误码,lpStat指向COMSTAT结构,用于存储当前串口的状态。 错误码表: CE_BREAK | 硬件检测到了一个中断情况 | CE_FRAME | 硬件检测到了一个帧错误 | CE_IOE | 硬件通信时发生一个I/O错误 | CE_MODE | 请求模式未被支持,或者hFile参数无效。如果指定了这个错误,那么它就是唯一的合法错误。 | CE_OVERRUN | 字符缓冲区被侵占,下一个字符丢失 | CE_RXOVER | 输入缓冲区溢出。输入缓冲区没有空间或者收到end-of-file (EOF)字符后又收到字符 | CE_RXPARITY | 硬件检测到奇偶校验错误 | CE_TXFULL | 应用程序试图发送一个字符,但输出缓冲区已满 | | |
COMSTAT结构体: typedef struct _COMSTAT { DWORD fCtsHold : 1; DWORD fDsrHold : 1; DWORD fRlsdHold : 1; DWORD fXoffHold : 1; DWORD fXoffSent : 1; DWORD fEof : 1; DWORD fTxim : 1; DWORD fReserved : 25; DWORD cbInQue; DWORD cbOutQue; } COMSTAT, *LPCOMSTAT; fCtsHold:表示是否正在等待CTS (Clear to Send)信号。 fDsrHold:表示是否正在等待DSR (Data Set Ready)信号。 fRlsdHold:表示是否正在等待RLSD (Receive Line Signal Detect)(接收线路信号检测,也叫载波检测)信号。 fXoffHold:表示是否因为收到XOFF字符而等待。 fXoffSent:表示是否因为驱动程序发送XOFF字符而等待。 fEof:表示是否收到End of File (EOF)字符。 fTxim:如果是1,表示队列中的字符是由TransmitCommChar函数写入的而不是WriteFile函数。 fReserved:保留,未用。 cbInQue:表示接收缓冲区中存储的待ReadFile读取的字节数。 cbOutQue:表示发送缓冲区中存储的待发送的字节数。 例: DWORD dwReadErrors; COMSTAT cmState; ClearCommError(m_hComm,&dwReadErrors,&cmState); | recv函数
发表评论