wince 串口 编程

串口的操作一般分为打开串口、配置串口、读写串口和关闭串口

一、打开串口 CreateFile

函数原型:

HANDLE CreateFile(LPCTSTR lpFileName, 
DWORD dwDesiredAccess, 
DWORD dwShareMode, 
LPSECURITY_ATTRIBUTES lpSecurityAttributes, 
DWORD dwCreationDistribution, 
DWORD dwFlagsAndAttributes, 
HANDLE hTemplateFile);

参数说明:
lpFileName:指向一个以NULL结束的字符串,该串指定了要创建、打开或截断的文件。
当用createFile打开串口时,这个参数可用”COM1“指定串口1,用”COM2“指定串口2。
dwDesiredAccess:指定对文件访问的类型,可以是读取、写入或二者并列(GENERIC_READ、GENERIC_WRITE)
dwShareMode:指定此文件可以怎样被共享,由于串口不能共享,因此是独占方式,即该参数必须置为0。
共享属性(FILE_SHARE_READ、FILE_SHARE_WRITE)
lpSecurityAttributes:定义安全性属性,一般不用,可设置为NULL;
dwCreationDistribution:定义文件创建方式,对串口操作必须置为OPEN_EXISTING(打开而不是创建);
dwFlagsAndAttributes:定义文件的属性和标志,用于指定该串口是否进行异步操作,
该值为FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,表示使用异步的I/O;
该值为0(FILE_ATTRIBUTE_NORMAL),表示同步I/O操作;
hTemplateFile:指向一个模板文件的句柄。串口无模板可言,因此对串口而言该参数必须置为NULL;
返回值:串口被成功打开时,返回其句柄,否则返回INVALID_HANDLE_VALUE(0XFFFFFFFF)

二、配置串口函数

1、_DCB说明
在打开通讯设备句柄后,常常需要对串口进行一些初始化配置工作,这需要通过一个DCB结构来进行。
DCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区。
一般用CreateFile打开串口后,可以调用GetCommState函数来获取串口的初始配置。要修改串口的配置,应该先修改DCB结构,然后再调用SetCommState函数设置串口。
DCB结构包含了串口的各项参数设置:

typedef struct _DCB{
	DWORD DCBlength;          
	//DCB结构体大小,即sizeof(_DCB),在调用SetCommState来更新DCB前必须作设置
	DWORD BaudRate;
	//波特率,指定通信设备的传输速率。这个成员可以是实际波特率值或者下面的常量值之一:
	//CBR_110,CBR_300,CBR_600,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_19200,     
    //CBR_38400,CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000
	DWORD fBinary:1;
	//指定是否允许二进制模式。Win32 API不支持非二进制模式传输,应设置为true
	DWORD fParity:1;
	//指定是否允许奇偶校验。若此成员为1,允许奇偶校验检查,具体采用何种校验根据Parity成员的设置
	DWORD fOutxCtsFlow:1; 
	//是否监控CTS(clear-to-send)信号来做输出流控(指定cts是否用于检测发送控制)。
    //当设置为true时:若CTS为低电平/off,则数据发送将被挂起,直至CTS变为高。 
	DWORD fOutxDsrFlow:1;
	//是否监控DSR (data-set-ready) 信号来做输出流控。
    //当设置为true时:若DSR为低电平,则数据发送将被挂起,直至DSR变为高。DSR的信号一般由DCE来控制
	DWORD fDtrControl:2;
	//DTR (data-terminal-ready)流控,可取值如下: 
    //DTR_CONTROL_DISABLE 打开设备时置DTR信号为低电平,应用程序可通过调用EscapeCommFunction函数来改变DTR线电平状态 
    //DTR_CONTROL_ENABLE 打开设备时置DTR信号为高电平,应用程序可通过调用 EscapeCommFunction     函数来改变DTR线电平状态 
    //DTR_CONTROL_HANDSHAKE 允许DTR信号握手,此时应用程序不能调用EscapeCommFunction函数 
	DWORD fDsrSensitivity:1;
	// 当该值为TRUE时DSR为OFF时接收的字节被忽略
	DWORD fTXContinueOnXoff:1;
	//TRUE时,不管接收端是否Xoff, 本方发送端持续发送。
    //(也就是本方的发送端, 与本方接收端Xon/Xoff是相互独立的)。
	//若为False 时,则当接收端buffer 达到XoffLim时,发送端发送完Xoff字符后,就停止发送。 
	DWORD fOutX:1; 
	//Xon和Xoff流量控制在发送时是否可用。
    //如果为true,当XOFF 值被收到的时候,发送停止;当 XON 值被收到的时候,发送继续。
	DWORD fInX:1; 
	//Xon和Xoff流量控制在接收时是否可用。
    //如果为TRUE, 当输入缓冲区已接收满XoffLim 字节时,发送XOFF字符;
    //当输入缓冲区已经有XonLim 字节的空余容量时,发送XON字符 
	DWORD fErrorChar:1; 
	//该值为TRUE,则用ErrorChar指定的字符代替奇偶校验错误的接收字符。
	DWORD fNull:1;
	//true时,接收时去掉空(0值)字节
	DWORD fRtsControl:2;
	//设置RTS (request-to-send)流控,若为0则缺省取 RTS_CONTROL_HANDSHAKE。可取值及其意义: 
    //RTS_CONTROL_DISABLE 打开设备时置RTS信号为低电平,应用程序可通过调用EscapeCommFunction函数来改变RTS线电平状态 
    //RTS_CONTROL_ENABLE 打开设备时置RTS信号为高电平,应用程序可通过调用EscapeCommFunction函数来改变RTS线电平状态 
    //RTS_CONTROL_HANDSHAKE 允许RTS信号握手,此时应用程序不能调用EscapeCommFunction函数。 
    //当输入缓冲区已经有足够空间接收数据时,驱动程序置RTS为高以允许DCE来发送;反之置RTS为低以阻止DCE发送数据。 
    //RTS_CONTROL_TOGGLE 有字节要发送时RTS变高,当所有缓冲字节已被发送完毕后,RTS变低。
	DWORD fAbortOnError:1;
	//true时,当发生错误时停止读写
	DWORD fDummy2:17;
	//保留,未启用
	WORD wReserved;
	//未启动,必须设置为0
	WORD XonLim;
	//在XON字符发送前接收缓冲区内可允许的最小字节数。
    //当接收Buffer中的字符减少到XonLim规定的字符数, 就发送Xon字符,让对方继续发送。
	WORD XoffLim;
	//在XOFF字符发送前接收缓冲区内可允许的最大字节数。
    //当接收Buffer达到XoffLim规定的字符数, 就发送Xoff字符, 让对方停止发送
	BYTE ByteSize;
	//通信数据位数,4-8
	BYTE Parity;
	//指定奇偶校验方法。此成员可以有下列值:
	//EVENPARITY 偶校验 
	//NOPARITY 无校验
	//MARKPARITY 标记校验 
	//ODDPARITY 奇校验
	BYTE StopBits;
	//指定停止位的位数。此成员可以有下列值:
	//ONESTOPBIT 1位停止位 
	//TWOSTOPBITS 2位停止位
	//ONE5STOPBITS 1.5位停止位
	char XonChar;
	//指定Xon字符
	char XoffChar;
	//指定Xoff字符
	char ErrorChar;
	//指定ErrorChar字符,奇偶校验发生错误时使用的字节
    //(本字符用来代替接收到的奇偶校验发生错误时的值)
	char EofChar;
	//EOF替代字符(当没有使用二进制模式时,用来标识数据结束的字符)
	char EvtChar;
	//事件触发字符,即接收到此字符时会产生一个事件
	WORD wReserved1;
	//保留,未启用
}DCB;

注:
1)流控分为硬件流控和软件流控。其中:硬件流控分为rts/cts和dtr/dsr两种,软件流控分为Xon/Xoff。
2)软件流控Xon/Xoff相关的参数:fOutX、fInX、XonLim、XoffLim、XonChar、XoffChar
fOutX:发送端支持Xon/Xoff。收到Xoff停止发送,收到Xon重新开始
fInX:接收端支持Xon/Xoff。当FIFO中字节超过XoffLim时发送Xoff, 当FIFO中少于XonLim时发送Xon
XonLim:当接收Buffer中的字符减少到XonLim规定的字符数, 就发送Xon字符,让对方继续发送
XoffLim:接收Buffer达到XoffLim规定的字符数, 就发送Xoff字符, 让对方停止发送
XonChar:Xon 字符
charXoffChar:Xoff 字符
fTXContinueOnXoff:;TRUE时,不管接收端是否Xoff, 本方发送端持续发送。 (也就是本方的发送端, 与本方接收端Xon/Xoff是相互独立的)。
若为False 时,则当接收端buffer 达到XoffLim时,发送端发送完Xoff字符后,就停止发送
3)DTR/DSR硬件流控:
3.1)fOutxDsrFlow:true时,支持DSR流控制。当DSR为off时,停止发送
3.2)fDtrControl:DTR设置,有如下值:
fDTRControlDTR_CONTROL_Disable:使DTR为off
DTR_CONTROL_Enable:使DTR为on
DTR_CONTROL_HANDSHAKE:DTR硬件流控
3.3)fDsrSensitivity:true时,当DSR为OFF,则接收端忽略所有字符。
4)RTS/CTS硬件流控:
4.1)fOutxCtsFlow:true时,支持ctsl流控制,当cts为off时,停止发送
4.2)fRtsControl:rts设置,有如下值:
fRTSControlRTS_CONTROL_DISABLE:使RTS保持 off
RTS_CONTROL_ENABLE:使RTS保持on
RTS_CONTROL_HANDSHAKE:RTS硬件流控
RTS_CONTROL_TOGGLE:485通讯RTS自动流控

2、GetCommState 和 SetCommState函数
函数原型:
BOOL GetCommState(HANDLE hFile, LPDCB lpDCB);
BOOL SetCommState(HANDLE hFile, LPDCB lpDCB);
获得/设置COM口的设备控制块,从而获得相关参数。
参数说明:
hFile:标识通讯端口的句柄
lpDCB:指向一个设备控制块(DCB结构)的指针

3、SetupComm函数
函数原型:
BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);
设置串行口的输入和输出缓冲区的大小
hFile:通信设备的句柄
dwInQueue:输入缓冲区的大小(字节数)
dwOutQueue:输出缓冲区的大小(字节数)
注:
除了在BCD中的设置外,程序一般还需要设置I/O缓冲区的大小和超时。Windows用I/O缓冲区来暂存串口输入和输出的数据。
如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。

4、GetCommTimeouts和SetCommTimeouts函数
函数原型:
BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
参数说明:
hFile:通信设备的句柄
lpCommTimeouts:设置的超时时间
查询/设置当前的超时设置,该函数会填充一个COMMTIMEOUTS结构。
超时的作用是在指定的时间内没有读入或发送指定数量的字符,ReadFile或WriteFile的操作仍然会结束。
读写串口的超时有两种:间隔超时和总超时。
间隔超时是指在接收时两个字符之间的最大时延。总超时是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。用COMMTIMEOUTS结构可以规定读写操作的超时。
COMMTIMEOUTS结构的成员都以毫秒为单位。
COMMTIMEOUTS结构定义为

typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout; //读间隔超时
DWORD ReadTotalTimeoutMultiplier; //读时间系数
DWORD ReadTotalTimeoutConstant; //读时间常量
DWORD WriteTotalTimeoutMultiplier; // 写时间系数
DWORD WriteTotalTimeoutConstant; //写时间常量
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

注:
总超时的计算公式:
总超时=时间系数×要求读/写的字符数+时间常量
例如,要读入10个字符,那么读操作的总超时的计算公式为:
读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant
注:
1)间隔超时和总超时的设置是不相关的
2)写操作只支持总超时,而读操作两种超时均支持

5、PurgeComm函数
函数原型:
BOOL PurgeComm(HANDLE hFile, DWORD dwFlags);
清空缓冲区
参数说明:
hFile:通信设备的句柄
dwFlags:需要完成的操作,可以是下列值的组合:
PURGE_TXABORT 中断所有写操作并立即返回,即使写操作还没有完成。
PURGE_RXABORT 中断所有读操作并立即返回,即使读操作还没有完成。
PURGE_TXCLEAR 清除输出缓冲区
PURGE_RXCLEAR 清除输入缓冲区

6、EscapeCommFunction函数
函数原型:
BOOL EscapeCommFunction( HANDLE hFile, DWORD dwFunc);
可将硬件信号置ON或OFF,模拟XON或XOFF
参数说明:
hFile:通信设备的句柄
dwFunc 事件掩码:
CLRDTR DTR置OFF
CLRRTS RTS置OFF
SETDTR STR置ON
SETRTS TRS置ON
SETXOFF 模拟XOFF字符的接收
SETXON 模拟XON字符的接收
SETBREAK 在发送中产生一个中止
CLRBREAK 在发送中清除中止

7、ClearCommError函数
函数原型:
BOOL ClearCommError(HANDLE hFile, LPDWORD lpErrors,LPCOMSTAT lpStat);
清除串行端口错误、读取串行端口现在的状态(清除串口的错误标志以便继续输入、输出操作),Windows系统利用此函数清除硬件的通讯错误以及获取通讯设备的当前状态。
参数说明:
hFile:通信设备的句柄
lpErrors:接收错误代码变量的类型,错误常数如下:
CE_BREAK:检测到中断信号
CE_DNS:Windows95专用,未被选择的并行端口
CE_FRAME:帧错误
CW_IOE:一般I/O错误,常伴有更为详细的错误标志
CE_MODE:不支持请求的模式
CE_OVERRUN:缓冲区超限下一个字符将丢失
CE_RXOVER:接收缓冲区超限
CE_RXPARITY:奇偶校验错误
CE_TXFULL:发送缓冲区满
CE_DNS:没有选择并行设备
CE_PTO:并行设备发生超时
CE_OOP:并行设备缺纸
lpStat:通信状态缓冲区的指针,指向一个COMSTAT结构,该结构返回串口状态信息。
COMSTAT结构包含串口的信息,结构定义如下:

typedef struct _COMSTAT { // cst 
		DWORD fCtsHold : 1; 
        // Tx waiting for CTS signal(为真时,等待cts信号开启传输)
		DWORD fDsrHold : 1; 
        // Tx waiting for DSR signal (为真时,等待dsr信号时开启传输)
		DWORD fRlsdHold : 1; 
        // Tx waiting for RLSD signal 
		DWORD fXoffHold : 1; 
        // Tx waiting, XOFF char rec’’d (为真时,等待接收到xoff时开始传输)
		DWORD fXoffSent : 1; 
        // Tx waiting, XOFF char sent 
		DWORD fEof : 1; 
        // EOF character sent (为真时,eof字符可以被收到)
		DWORD fTxim : 1; 
        // character waiting for Tx 
		DWORD fReserved : 25; 
        // reserved (保留)
		DWORD cbInQue; 
        // bytes in input buffer //串口接收缓冲区的字节数,它们还没有来得及被ReadFile操作读走
		DWORD cbOutQue; 
        // bytes in output buffer  //串口发送缓冲区的字节数
}

8、GetCommMask和SetCommMask函数
函数原型:
BOOL GetCommMask(HANDLE hFile, LPDWORD lpEvtMask);
BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask);
设置/获取监听事件
参数说明:
hFile:通信设备的句柄
EvtMask:事件掩码,标识将被监视的通信事件。如果该参数设置为0,则表示禁止所有事件。如果不为0,则掩码可为如下:

EV_BREAK 检测到输入为止
EV_CTS CTS(清除发送)信号改变状态
EV_DSR DSR(数据设置就绪)信号改变状态
EV_ERR 发生了线路状态错误.
CE_FRAME(帧错误)
CE_OVERRUN(接收缓冲区超限)
CE_RXPARITY(奇偶校验错误)
EV_RING 检测到振铃
EV_RLSD RLSD(接收线路信号检测)信号改变状态
EV_EXCHAR 接收到一个字符,并放入输入缓冲区
EV_RXFLAG 接收到事件字符(DCB成员的EvtChar成员),度放入输入缓冲区
EV_TXEMPTY 输出缓冲区中最后一个字符发送出去
//在用SetCommMask指定了有用的事件后,应用程序可调用WaitCommEvent()来等待事件发生.

9、WaitCommEvent函数
函数原型:
BOOL WaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
等待被监控事件发生
参数说明:
hFile:通信设备的句柄
lpEvtMask:指向一个32位变量,接收事件掩模,标识所发生的通信事件属于何种类型
lpOverlapped:指向一个OVERLAPPED结构,如果打开hFile表示的通信设备时,指定FILE_FLAG_OVERLAPPED标志,则该参数被忽略。如果不需要异步操作,则这个参数不用设置。

三、串口读写函数
1、读函数
函数原型:
BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
读串口数据
参数说明:
hFile:串口的句柄
lpBuffer:读入的数据存储的地址,即读入的数据将存储在以该指针的值为首地址的一片内存区
nNumberOfBytesToRead:要读入的数据的字节数
lpNumberOfBytesRead:指向一个DWORD数值,该数值返回读操作实际读入的字节数
lpOverlapped:重叠(异步)操作时,该参数指向一个OVERLAPPED结构;同步操作时,该参数为NULL。

2、写函数
函数原型:
BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped);
写串口函数
函数说明:
hFile:串口的句柄
lpBuffer:即以该指针的值为首地址的nNumberOfBytesToWrite个字节的数据将要写入串口的发送数据缓冲区。
nNumberOfBytesToWrite:将要写入的数据的字节数
lpNumberOfBytesWritten:指向一个DWORD数值,该数值返回实际写入的字节数
lpOverlapped:重叠(异步)操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL。

OVERLAPPED用于记录了当前正在操作的文件一些相关信息,OVERLAPPED结构说明:
typedef struct _OVERLAPPED {
	DWORD Internal;
    //保存已处理的I/O请求的错误码/状态码
	DWORD InternalHigh;
    //当异步I/O请求完成的时候,这个成员用来保存已传输的字节数。
	DWORD Offset;
    //该文件的位置是从文件起始处的字节偏移量。调用进程设置这个成员之前调用ReadFile或WriteFile函数。当读取或写入命名管道和通信设备时这个成员被忽略设为零。
	DWORD OffsetHigh;
    //指定文件传送的 字节 偏移量的高位字。当读取或写入命名管道和通信设备时这个成员被忽略设为零。
	HANDLE hEvent;
    //在转移完成时处理一个事件设置为有信号状态。
    //调用进程集这个成员在调用ReadFile、 WriteFile、TransactNamedPipe、 ConnectNamedPipe函数之前。
} OVERLAPPED;

3、GetOverlappedResult函数
函数原型:
BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait);
根据OVERLAPPED结构来获取重叠操作的状态/结果,用来判断异步操作是否完成,它是通过判断OVERLAPPED结构中的hEvent是否被置位来
参数说明:
hFile:串口的句柄
lpOverlapped:指向重叠操作开始时指定的OVERLAPPED结构
lpNumberOfBytesTransferred:指向一个32位变量,该变量的值返回实际读写操作传输的字节数
bWait:该参数用于指定函数是否一直等到重叠操作结束。如果该参数为TRUE,函数直到操作结束才返回;
如果该参数为FALSE,函数直接返回,这时如果操作没有完成,通过调用GetLastError()函数会返回ERROR_IO_INCOMPLETE。

注:
1)ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作;而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
2)如果成功,两个函数都返回TRUE。当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastError函数分析返回的结果。
例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且 GetLastError函数返回ERROR_IO_PENDING,这说明重叠操作还未完成。
3)在使用ReadFile和WriteFile重叠操作时,线程需要创建OVERLAPPED结构以供这两个函数使用。线程通过OVERLAPPED结构获得当前的操作状态,该结构最重要的成员是hEvent。
hEvent是读写事件。当串口使用异步通讯时,函数返回时操作可能还没有完成,程序可以通过检查该事件得知是否读写完毕。
当调用ReadFile, WriteFile 函数的时候,该成员会自动被置为无信号状态;当重叠操作完成后,该成员变量会自动被置为有信号状态。

猜你喜欢

转载自blog.csdn.net/qq_33782617/article/details/122388095