VC++串口编程主要API详解
该文档是本人在刚刚接触到VC++下的串口编程时,总结归纳的一些主要的API函数,可以帮助初学者更好的理解串口编程的方法。
1. 打开串口
HANDLE CreateFile( LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes, hTemplateFile);
HANDLE
参数:
lpFileName:将要打开的串口逻辑名,如“COM1”;
dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;
dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0;
lpSecurityAttributes:引用安全性属性结构,缺省值为NULL;
dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING;
dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作,本工程采用异步方式;
hTemplateFile:对串口而言该参数必须置为NULL;
2. 获取串口设备控制块DCB
BOOL GetCommState(
HANDLE hFile, //标识通讯端口的句柄,由CreateFile()函数返回的句柄
LPDCB lpDCB //指向一个设备控制块(DCB结构)的指针
);
3. 设置串口设备控制块DCB
BOOL SetCommState(
HANDLE hFile, //标识通讯端口的句柄,由CreateFile()函数返回的句柄
LPDCB lpDCB //指向一个设备控制块(DCB结构)的指针
);
4. 设置串口输入输出缓冲区大小
BOOL SetupComm(
HANDLE hFile, // 通信设备的句柄
DWORD dwInQueue, // 输入缓冲区的大小(字节数)
DWORD dwOutQueue // 输出缓冲区的大小(字节数)
);
5. 清空读写缓冲区内容
BOOL PurgeComm(
HANDLE hFile, //串口句柄
DWORD dwFlags // 需要完成的操作
);
参数dwFlags指定要完成的操作,可以是下列值的组合:
PURGE_TXABORT 中断所有写操作并立即返回,即使写操作还没有完成。
PURGE_RXABORT 中断所有读操作并立即返回,即使读操作还没有完成。
PURGE_TXCLEAR 清除输出缓冲区
PURGE_RXCLEAR 清除输入缓冲区
6. 超时时间获取与设置
BOOL GetCommTimeouts( //获取串口超时设置
HANDLE hFile, //标识通信设备,CreateFile()函数返回该句柄;
LPCOMMTIMEOUTS lpCommTimeouts //指向COMMTIMEOUTS结构。
);
BOOL SetCommTimeouts( //设置串口超时时间
HANDLE hFile, //标识通信设备,CreateFile()函数返回该句柄;
LPCOMMTIMEOUTS lpCommTimeouts //指向COMMTIMEOUTS结构。
);
COMMTIMEOUTS结构的定义为:
typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout; //读间隔超时,单位ms
DWORD ReadTotalTimeoutMultiplier; //读时间系数,单位ms
DWORD ReadTotalTimeoutConstant; //读时间常量,单位ms
DWORD WriteTotalTimeoutMultiplier; // 写时间系数,单位ms
DWORD WriteTotalTimeoutConstant; //写时间常量,单位ms
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
参数详解:
·ReadIntervalTimeout:以ms为单位指定通信线路上两个字符到达之间的最大时间间隔。 在ReadFile()操作期间,从接收到第一个字符时开始计时。如果任意两个字符到达之间的时间间隔超过这个最大值,则ReadFile()操作完成,并返回缓冲数据。如果被置为0,则表示 不使用间隔超时。
Windows使用下面的式子计算总超时时间:
ReadTotalTimeout
( ReadTotalTimeoutMultiplier*bytes_to_read )+ReadTotalTimeoutConstant;
=
WriteTotalTimeout=
( WriteTotalTimeoutMultiplier*bytes_to_write )+WriteTotalTimeoutConstant;
超时有两种类型。第一种类型叫区间超时(intervaltimeout),它仅适应于从端口读取数据
它指定在读取两个字符之间要经历多长时间。接收一个字符时,Windows就启动一个内部计
时器。在下一个字符到达之前,如果定时器超过了区间超时设定时间,读函数就会放弃。第
二种类型的超时叫做总超时( total timeout),它适于读和写端口。当读或写特定字节数需
要的总时间超过某一阈值时,该超时即被触发。
当超时的常数和系数都设置为0,则没有总超时时间。如果读间隔超时被设置成MAXDWORD并且读时间系数和读时间常量都为0,那么在读一次输入缓冲区的内容后读操作就立即返回而不管是否读入了要求的字符。
在用异步方式读写串口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile
和WriteFile的返回时间。
7. 关闭串口
BOOL CloseHandle(
HANDLE hObject; //串口句柄
);
8. 读写串口
BOOL ReadFile(
HANDLE hFile, //串口的句柄
LPVOID lpBuffer, // 读入的数据存储的地址,
DWORD nNumberOfBytesToRead, // 要读入的数据的字节数
LPDWORD lpNumberOfBytesRead, // 指向一个DWORD数值,该数值返回读操作实际读入的字节数
LPOVERLAPPED lpOverlapped 结构,同步操作时,该参数为NULL。
// 异步操作时,该参数指向一个OVERLAPPED
);
BOOL WriteFile(
HANDLE hFile, //串口的句柄
LPCVOID lpBuffer, // 写入的数据存储的地址,
DWORD nNumberOfBytesToWrite, //要写入的数据的字节数
LPDWORD lpNumberOfBytesWritten, // 指向指向一个DWORD数值,该数值返回实际写入的字节数
LPOVERLAPPED lpOverlapped 结构, 同步操作时,该参数为NULL。
// 重叠操作时,该参数指向一个OVERLAPPED
);
在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从而导致效率下降。在异步执行时,即使操作还未完成,这两个函数也会立即返回,费时的I/O操作在后台进行。
如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,应该调用GetLastError函数分析返回的结果。例如,在异步操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING。这说明异步操作还未完成。
9. 清除错误
BOOL ClearCommError(
HANDLE hFile, // 串口句柄
LPDWORD lpErrors, // 指向接收错误码的变量
LPCOMSTAT lpStat // 指向通讯状态缓冲区
);
该函数获得通信错误并报告串口的当前状态,同时,该函数清除串口的错误标志以便继续输入、输出操作。
在使用ReadFile 函数进行读操作前,应先使用ClearCommError函数清除错误。
参数lpStat指向一个COMSTAT结构,该结构返回串口状态信息。 COMSTAT结构 COMSTAT结构包含串口的信息,结构定义如下:
typedef struct _COMSTAT { // cst
DWORD fCtsHold : 1; // Tx waiting for CTS signal
DWORD fDsrHold : 1; // Tx waiting for DSR signal
DWORD fRlsdHold : 1; // Tx waiting for RLSD signal
DWORD fXoffHold : 1; // Tx waiting, XOFF char rec''d
DWORD fXoffSent : 1; // Tx waiting, XOFF char sent
DWORD fEof : 1; // EOF character sent
DWORD fTxim : 1; // character waiting for Tx
DWORD fReserved : 25; // reserved
DWORD cbInQue; // bytes in input buffer
DWORD cbOutQue; // bytes in output buffer
} COMSTAT, *LPCOMSTAT;
10. 设置通讯端口监听事件
BOOL SetCommMask(
HANDLE hFile, //标识通信端口的句柄
DWORD dwEvtMask //能够使能的通信事件
);
通讯端口的事件由dwEvtMask变量来设置,其可取如下值:
EV_BREAK 检测到输入为止
EV_CTS CTS (清除发送)信号改变状态
EV_DSR DSR (数据设置就绪)信号改变状态
EV_ERR 发生了线路状态错误.
线路状态错误为:
CE_FRAME(帧错误)
CE_OVERRUN(接收缓冲区超限)
CE_RXPARITY(奇偶校验错误)
EV_RING 检测到振铃
EV_RLSD RLSD (接收线路信号检测)信号改变状态
EV_RXCHAR 接收到一个字符,并放入输入缓冲区
EV_RXFLAG 使用SetCommState()函数设置的DCB结构中的等待字符已被传入输入缓冲区中。
EV_TXEMPTY 输出缓冲区中最后一个字符发送出去
在用SetCommMask指定了有用的事件后,应用程序可调用WaitCommEvent()来等待事件发生。
11. 获取端口监听事件
BOOL GetCommMask(
HANDLE hFile, //标识通信端口的句柄
LPDWORD lpEvtMask //存储监控的通信事件
);
12. 等待监听事件发生
BOOL WaitCommEvent(
HANDLE hFile, //标识通信端口的句柄
LPDWORD lpEvtMask, //指向存放事件标识变量的指针
LPOVERLAPPED lpOverlapped // 指向overlapped结构
);
该函数调用成功返回TURE,若失败则返回FALSE。
若函数返回FALSE,可调用GetLastError()查看错误类型,如过错误类型是ERROR_IO_PENDING,表明没有检测到事件发生,程序继续在后台进行监听,并且LPOVERLAPPED结构的hEvent成员变量被设置为无信号状态;若返回成功,表示检测到某个事件发生,具体是哪个类型的事件发生可通过查看lpEvtMask参数获知。
lpEvtMask参数的值只可能是SetCommMask()函数设置的的监听通讯端口事件。此时LPOVERLAPPED 结构的hEvent成员变量被设置为有信号状态。
因篇幅问题不能全部显示,请点此查看更多更全内容