收藏 分享(赏)

vc++串口编程.doc

上传人:ysd1539 文档编号:7336274 上传时间:2019-05-15 格式:DOC 页数:36 大小:297.50KB
下载 相关 举报
vc++串口编程.doc_第1页
第1页 / 共36页
vc++串口编程.doc_第2页
第2页 / 共36页
vc++串口编程.doc_第3页
第3页 / 共36页
vc++串口编程.doc_第4页
第4页 / 共36页
vc++串口编程.doc_第5页
第5页 / 共36页
点击查看更多>>
资源描述

1、深入浅出 VC+串口编程之基本概念 2006-02-17 09:43 作者:宋宝华出处:天极开发责任编辑:方舟引言在 PC 机的主板上,有一种类型的接口可能为我们所忽视,那就是 RS-232C 串行接口,在微软的Windows 系统中称其为 COM。我们可以通过设备管理器来查看 COM 的硬件参数设置,如图 1。图 1 在 Windows 上查看 PC 串口设置迄今为止,几乎每一台 PC 都包含 COM。本质而言,COM 是 PC 为和外界通信所提供的一种串行数据传输的接口。作为一种物理通信的途径和设备,它和目前风靡的另一种串行接口USB 所提供的功能是一致的。不过 RS-232C 显然已经开

2、始被后起之秀 USB 赶超,因为 USB 的传输速率已经远远超过了RS-232C。尽管如此,RS-232C 仍然具有非常广泛的应用,在相对长的一段时间里,难以被 USB 等接口取代。RS-232C 接口(又称 EIA RS-232C),1970 年由美国电子工业协会(EIA )联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定,全名是“数据终端设备(DTE)和数据通讯设备(DCE )之间串行二进制数据交换接口技术标准“。本文将对这一接口进行硬件原理的介绍,随后我们将逐章学习 DOS 平台的串口编程,及 Windows平台下基于 API、控件和第三方类的串口编程,最后本文将给出一个综合实例

3、。在本文的连载过程中,您可以通过如下方式联系作者(热忱欢迎读者朋友对本文的内容提出质疑或给出修改意见):作者 email:(可以来信提问,笔者将力求予以回信解答,并摘取其中的典型问题,在本系列文章最后一次连载的读者反馈中予以阐述);硬件原理众所周知,CPU 与存储芯片和 I/O 芯片的通信是并行的(并行传输的最大位数依赖于 CPU 的字长、数据总线的宽度),一种叫做 UART(通用异步收发器,Universal Asynchronous Receiver/Transmitter)的芯片提供了并行数据传输和 RS-232C 串行数据传输方式的转换。这样的设备通常有如图 2 所示的管脚分布,当其向

4、外传输数据时,CPU 并行的将数据写入这类芯片的寄存器, UART再将寄存器中的数据一位一位地移动并向外传输;当外界向其传输数据时,UART 一位一位地接收数据,并将其移位组合为并行数据,CPU 再并行地读取这些数据。实际上,由于 UART 芯片一般以 TTL/CMOS电平工作,在 UART 连接接口之前,还要经过一个 TTL/CMOS 和 RS-232C 电平的转换。RS-232C 规定了其标准的电气特性,逻辑 1 对应的电压必须在-5-15V 之间;逻辑 0 对应的的电压必须在+5+15V 之间。图 2 UART 并/串转换一个常见的 TTL/CMOS 和 RS-232C 电平转换芯片如图

5、 3。图 3 常见的 TTL/CMOS 和 RS-232C 电平转换芯片RS-232C 通常以两类接插件与外界相连,分别称为 DB9 和 DB25,如图 4 所示。图 4 DB9 和 DB25而接插件中各个针的定义则如表 1:表 1 DB9 和 DB25 引脚定义DB9 DB25针号 功能说明 缩写 针号 功能说明 缩写1 数据载波检测 DCD 8 数据载波检测 DCD2 接收数据 RXD 3 接收数据 RXD3 发送数据 TXD 2 发送数据 TXD4 数据终端准备 DTR 20 数据终端准备 DTR5 信号地 GND 7 信号地 GND6 数据设备准备好 DSR 6 数据准备好 DSR7

6、请求发送 RTS 4 请求发送 RTS8 清除发送 CTS 5 清除发送 CTS9 振铃指示 DELL 22 振铃指示 DELLRS-232C 定义为数据通信设备(DCE)和数据终端设备(DTE)之间的互连,实现上,到现在为止,究竟一个设备属于 DCE 还是属于 DTE 已经没有明显的界限,PC 即可作为 DCE,又可作为 DTE。两串口互连,连接方法主要有二:一种方法是,数据的发送和接收由软件控制,不进行硬件握手,其连接方法如图 5(最常用 DB9 连接示意)和表 2( DB9、DB25 三线连接表),真正需要互相连接的是 RXD、TXD 和 GND;图 5 无硬件握手时两串口连接表 2 D

7、B9、DB25 三线连接9 针9 针 5 针25 针 2 9 针 25 针2 3 3 2 2 23 2 2 3 3 3 5 5 7 7 5 7 软件握手又称为 XON/XOFF,通常以 CTRL-S(0x13)和 CTRL-Q(0x11 )两个字符来实现流控制。前者用于请求对方暂停发送,后者用于清除暂停传送的请求,继续发送数据。另一种方法是,数据的发送和接收由硬件控制,进行硬件握手,其连接方法如图 6(最常用 DB9 连接示意),需要连接的信号除 RXD、TXD 和 GND 外,还包括 DTR、DSR、RTS 和 CTS。硬件握手依赖于 RTS 和 CTS 信号,当发送设备欲发送数据时,将 R

8、TS 信号置为有效表示请求发送,接收设备准备好后,置 CTS 信号有效,接着发送设备通过信号线 TXD 开始发送串行数据。这里我们联想开来,RTS/CTS 模式在许多领域里都出现过。回忆一下 IEEE 802.11 无线局域网协议标准,在其 MAC 协议中就使用了 RTS/CTS,RTS/CTS 抽象开来就是一种请求/应答。笔者曾经在拙作中多次以实例论证计算机领域里许多知识的相通性,这又是一个明证。图 6 有硬件握手时两串口连接实际上,目前我们经常使用的是方法一,即只连接 RXD、TXD 和 GND,简单灵活。另外,串口之间互连还有诸多途径,如图 7 所示。图 7 其它互连方式Win32 串

9、口 编 程作 者 : 韩 耀 旭下 载 源 代 码在 工 业 控 制 中 , 工 控 机 ( 一 般 都 基 于 Windows 平 台 ) 经 常 需 要 与 智 能 仪 表 通过 串 口 进 行 通 信 。 串 口 通 信 方 便 易 行 , 应 用 广 泛 。一 般 情 况 下 , 工 控 机 和 各 智 能 仪 表 通 过 RS485 总 线 进 行 通 信 。 RS485 的 通 信 方式 是 半 双 工 的 , 只 能 由 作 为 主 节 点 的 工 控 PC 机 依 次 轮 询 网 络 上 的 各 智 能 控 制 单元 子 节 点 。 每 次 通 信 都 是 由 PC 机 通 过

10、 串 口 向 智 能 控 制 单 元 发 布 命 令 , 智 能 控 制 单元 在 接 收 到 正 确 的 命 令 后 作 出 应 答 。在 Win32 下 , 可 以 使 用 两 种 编 程 方 式 实 现 串 口 通 信 , 其 一 是 使 用 ActiveX控 件 , 这 种 方 法 程 序 简 单 , 但 欠 灵 活 。 其 二 是 调 用 Windows 的 API 函 数 , 这 种方 法 可 以 清 楚 地 掌 握 串 口 通 信 的 机 制 , 并 且 自 由 灵 活 。 本 文 我 们 只 介 绍 API 串口 通 信 部 分 。串 口 的 操 作 可 以 有 两 种 操 作

11、 方 式 : 同 步 操 作 方 式 和 重 叠 操 作 方 式 ( 又 称 为 异 步操 作 方 式 ) 。 同 步 操 作 时 , API 函 数 会 阻 塞 直 到 操 作 完 成 以 后 才 能 返 回 ( 在 多 线 程方 式 中 , 虽 然 不 会 阻 塞 主 线 程 , 但 是 仍 然 会 阻 塞 监 听 线 程 ) ; 而 重 叠 操 作 方 式 , API函 数 会 立 即 返 回 , 操 作 在 后 台 进 行 , 避 免 线 程 的 阻 塞 。无 论 那 种 操 作 方 式 , 一 般 都 通 过 四 个 步 骤 来 完 成 :( 1) 打 开 串 口( 2) 配 置 串

12、 口( 3) 读 写 串 口( 4) 关 闭 串 口( 1) 打 开 串 口 Win32 系 统 把 文 件 的 概 念 进 行 了 扩 展 。 无 论 是 文 件 、 通 信 设 备 、 命 名 管 道 、 邮件 槽 、 磁 盘 、 还 是 控 制 台 , 都 是 用 API 函 数 CreateFile 来 打 开 或 创 建 的 。 该 函 数的 原 型 为 : HANDLE CreateFile( LPCTSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttr

13、ibutes,DWORD dwCreationDistribution,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); lpFileName: 将 要 打 开 的 串 口 逻 辑 名 , 如 “COM1”; dwDesiredAccess: 指 定 串 口 访 问 的 类 型 , 可 以 是 读 取 、 写 入 或 二 者 并 列 ; dwShareMode: 指 定 共 享 属 性 , 由 于 串 口 不 能 共 享 , 该 参 数 必 须 置 为0; lpSecurityAttributes: 引 用 安 全 性 属 性 结 构 , 缺

14、省 值 为 NULL; dwCreationDistribution: 创 建 标 志 , 对 串 口 操 作 该 参 数 必 须 置 为OPEN_EXISTING; dwFlagsAndAttributes: 属 性 描 述 , 用 于 指 定 该 串 口 是 否 进 行 异 步 操 作 , 该值 为 FILE_FLAG_OVERLAPPED, 表 示 使 用 异 步 的 I/O; 该 值 为 0, 表 示 同步 I/O 操 作 ; hTemplateFile: 对 串 口 而 言 该 参 数 必 须 置 为 NULL; 同 步 I/O 方 式 打 开 串 口 的 示 例 代 码 : HAN

15、DLE hCom; /全 局 变 量 , 串 口 句 柄hCom=CreateFile(“COM1“,/COM1 口GENERIC_READ|GENERIC_WRITE, /允 许 读 和 写0, /独 占 方 式NULL,OPEN_EXISTING, /打 开 而 不 是 创 建0, /同 步 方 式NULL);if(hCom=(HANDLE)-1)AfxMessageBox(“打 开 COM 失 败 !“);return FALSE;return TRUE;重 叠 I/O 打 开 串 口 的 示 例 代 码 : HANDLE hCom; /全 局 变 量 , 串 口 句 柄hCom =Cr

16、eateFile(“COM1“, /COM1 口GENERIC_READ|GENERIC_WRITE, /允 许 读 和 写0, /独 占 方 式NULL,OPEN_EXISTING, /打 开 而 不 是 创 建FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, /重 叠 方 式NULL);if(hCom =INVALID_HANDLE_VALUE)AfxMessageBox(“打 开 COM 失 败 !“);return FALSE;return TRUE;( 2) 、 配 置 串 口 在 打 开 通 讯 设 备 句 柄 后 , 常 常 需 要 对 串

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

18、ate 函 数 设 置 串 口 。DCB 结 构 包 含 了 串 口 的 各 项 参 数 设 置 , 下 面 仅 介 绍 几 个 该 结 构 常 用 的 变 量 : typedef struct _DCB/波 特 率 , 指 定 通 信 设 备 的 传 输 速 率 。 这 个 成 员 可 以 是 实 际 波 特 率 值或 者 下 面 的 常 量 值 之 一 :DWORD BaudRate; CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400, CBR_4800, CBR_9600, CBR_19200, CBR_38400, CBR_56000, CBR

19、_57600, CBR_115200, CBR_128000, CBR_256000, CBR_14400DWORD fParity; / 指 定 奇 偶 校 验 使 能 。 若 此 成 员 为 1, 允 许 奇 偶 校 验检 查 BYTE ByteSize; / 通 信 字 节 位 数 , 48BYTE Parity; /指 定 奇 偶 校 验 方 法 。 此 成 员 可 以 有 下 列 值 :EVENPARITY 偶 校 验 NOPARITY 无 校 验MARKPARITY 标 记 校 验 ODDPARITY 奇 校 验BYTE StopBits; /指 定 停 止 位 的 位 数 。 此

20、 成 员 可 以 有 下 列 值 :ONESTOPBIT 1 位 停 止 位 TWOSTOPBITS 2 位 停 止 位ONE5STOPBITS 1.5 位 停 止 位 DCB;winbase.h 文 件 中 定 义 了 以 上 用 到 的 常 量 。 如 下 :#define NOPARITY 0#define ODDPARITY 1#define EVENPARITY 2#define ONESTOPBIT 0#define ONE5STOPBITS 1#define TWOSTOPBITS 2#define CBR_110 110#define CBR_300 300#define CB

21、R_600 600#define CBR_1200 1200#define CBR_2400 2400#define CBR_4800 4800#define CBR_9600 9600#define CBR_14400 14400#define CBR_19200 19200#define CBR_38400 38400#define CBR_56000 56000#define CBR_57600 57600#define CBR_115200 115200#define CBR_128000 128000#define CBR_256000 256000GetCommState 函 数

22、可 以 获 得 COM 口 的 设 备 控 制 块 , 从 而 获 得 相 关 参 数 : BOOL GetCommState(HANDLE hFile, /标 识 通 讯 端 口 的 句 柄LPDCB lpDCB /指 向 一 个 设 备 控 制 块 ( DCB 结 构 ) 的 指 针);SetCommState 函 数 设 置 COM 口 的 设 备 控 制 块 :BOOL SetCommState(HANDLE hFile, LPDCB lpDCB );除 了 在 BCD 中 的 设 置 外 , 程 序 一 般 还 需 要 设 置 I/O 缓 冲 区 的 大 小 和 超 时 。Windo

23、ws 用 I/O 缓 冲 区 来 暂 存 串 口 输 入 和 输 出 的 数 据 。 如 果 通 信 的 速 率 较 高 , 则 应该 设 置 较 大 的 缓 冲 区 。 调 用 SetupComm 函 数 可 以 设 置 串 行 口 的 输 入 和 输 出 缓 冲区 的 大 小 。 BOOL SetupComm(HANDLE hFile, / 通 信 设 备 的 句 柄 DWORD dwInQueue, / 输 入 缓 冲 区 的 大 小 ( 字 节 数 ) DWORD dwOutQueue / 输 出 缓 冲 区 的 大 小 ( 字 节 数 ));在 用 ReadFile 和 WriteF

24、ile 读 写 串 行 口 时 , 需 要 考 虑 超 时 问 题 。 超 时 的 作 用 是在 指 定 的 时 间 内 没 有 读 入 或 发 送 指 定 数 量 的 字 符 , ReadFile 或 WriteFile 的 操 作仍 然 会 结 束 。要 查 询 当 前 的 超 时 设 置 应 调 用 GetCommTimeouts 函 数 , 该 函 数 会 填 充 一 个COMMTIMEOUTS 结 构 。 调 用 SetCommTimeouts 可 以 用 某 一 个COMMTIMEOUTS 结 构 的 内 容 来 设 置 超 时 。读 写 串 口 的 超 时 有 两 种 : 间 隔

25、 超 时 和 总 超 时 。 间 隔 超 时 是 指 在 接 收 时 两 个 字 符之 间 的 最 大 时 延 。 总 超 时 是 指 读 写 操 作 总 共 花 费 的 最 大 时 间 。 写 操 作 只 支 持 总 超 时 ,而 读 操 作 两 种 超 时 均 支 持 。 用 COMMTIMEOUTS 结 构 可 以 规 定 读 写 操 作 的 超 时 。COMMTIMEOUTS 结 构 的 定 义 为 : typedef struct _COMMTIMEOUTS DWORD ReadIntervalTimeout; /读 间 隔 超 时DWORD ReadTotalTimeoutMult

26、iplier; /读 时 间 系 数DWORD ReadTotalTimeoutConstant; /读 时 间 常 量DWORD WriteTotalTimeoutMultiplier; / 写 时 间 系 数DWORD WriteTotalTimeoutConstant; /写 时 间 常 量 COMMTIMEOUTS,*LPCOMMTIMEOUTS;COMMTIMEOUTS 结 构 的 成 员 都 以 毫 秒 为 单 位 。 总 超 时 的 计 算 公 式 是 :总 超 时 时 间 系 数 要 求 读 /写 的 字 符 数 时 间 常 量 例 如 , 要 读 入 10 个 字 符 , 那

27、 么 读 操 作 的 总 超 时 的 计 算 公 式 为 :读 总 超 时 ReadTotalTimeoutMultiplier10 ReadTotalTimeoutConstant 可 以 看 出 : 间 隔 超 时 和 总 超 时 的 设 置 是 不 相 关 的 , 这 可 以 方 便 通 信 程 序 灵 活 地 设 置各 种 超 时 。 如 果 所 有 写 超 时 参 数 均 为 0, 那 么 就 不 使 用 写 超 时 。 如 果 ReadIntervalTimeout为 0, 那 么 就 不 使 用 读 间 隔 超 时 。 如 果 ReadTotalTimeoutMultiplier

28、 和 ReadTotalTimeoutConstant 都 为 0, 则 不 使 用 读 总 超 时 。 如 果 读 间 隔 超 时 被 设 置成 MAXDWORD 并 且 读 时 间 系 数 和 读 时 间 常 量 都 为 0, 那 么 在 读 一 次 输 入 缓 冲 区的 内 容 后 读 操 作 就 立 即 返 回 , 而 不 管 是 否 读 入 了 要 求 的 字 符 。在 用 重 叠 方 式 读 写 串 口 时 , 虽 然 ReadFile 和 WriteFile 在 完 成 操 作 以 前 就 可能 返 回 , 但 超 时 仍 然 是 起 作 用 的 。 在 这 种 情 况 下 ,

29、超 时 规 定 的 是 操 作 的 完 成 时 间 ,而 不 是 ReadFile 和 WriteFile 的 返 回 时 间 。配 置 串 口 的 示 例 代 码 : SetupComm(hCom,1024,1024); /输 入 缓 冲 区 和 输 出 缓 冲 区 的 大小 都 是 1024COMMTIMEOUTS TimeOuts;/设 定 读 超 时TimeOuts.ReadIntervalTimeout=1000;TimeOuts.ReadTotalTimeoutMultiplier=500;TimeOuts.ReadTotalTimeoutConstant=5000;/设 定 写

30、超 时TimeOuts.WriteTotalTimeoutMultiplier=500;TimeOuts.WriteTotalTimeoutConstant=2000;SetCommTimeouts(hCom, /设 置 超 时DCB dcb;GetCommState(hCom,dcb.BaudRate=9600; /波 特 率 为 9600dcb.ByteSize=8; /每 个 字 节 有 8 位dcb.Parity=NOPARITY; /无 奇 偶 校 验 位dcb.StopBits=TWOSTOPBITS; /两 个 停 止 位SetCommState(hCom,PurgeComm(h

31、Com,PURGE_TXCLEAR|PURGE_RXCLEAR);在 读 写 串 口 之 前 , 还 要 用 PurgeComm()函 数 清 空 缓 冲 区 , 该 函 数 原 型 : BOOL PurgeComm(HANDLE hFile, /串 口 句 柄DWORD dwFlags / 需 要 完 成 的 操 作);参 数 dwFlags 指 定 要 完 成 的 操 作 , 可 以 是 下 列 值 的 组 合 : PURGE_TXABORT 中 断 所 有 写 操 作 并 立 即 返 回 , 即 使 写 操 作 还 没 有 完 成 。PURGE_RXABORT 中 断 所 有 读 操 作

32、 并 立 即 返 回 , 即 使 读 操 作 还 没 有 完 成 。PURGE_TXCLEAR 清 除 输 出 缓 冲 区PURGE_RXCLEAR 清 除 输 入 缓 冲 区( 3) 、 读 写 串 口 我 们 使 用 ReadFile 和 WriteFile 读 写 串 口 , 下 面 是 两 个 函 数 的 声 明 : BOOL ReadFile(HANDLE hFile, /串 口 的 句 柄/ 读 入 的 数 据 存 储 的 地 址 ,/ 即 读 入 的 数 据 将 存 储 在 以 该 指 针 的 值 为 首 地 址 的 一 片 内 存 区LPVOID lpBuffer,DWORD

33、nNumberOfBytesToRead, / 要 读 入 的 数 据 的 字 节 数/ 指 向 一 个 DWORD 数 值 , 该 数 值 返 回 读 操 作 实 际 读 入 的 字 节 数LPDWORD lpNumberOfBytesRead,/ 重 叠 操 作 时 , 该 参 数 指 向 一 个 OVERLAPPED 结 构 , 同 步 操 作 时 ,该 参 数 为 NULL。LPOVERLAPPED lpOverlapped );BOOL WriteFile(HANDLE hFile, /串 口 的 句 柄/ 写 入 的 数 据 存 储 的 地 址 ,/ 即 以 该 指 针 的 值 为

34、 首 地 址 的 nNumberOfBytesToWrite/ 个 字 节 的 数 据 将 要 写 入 串 口 的 发 送 数 据 缓 冲 区 。LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite, /要 写 入 的 数 据 的 字 节 数/ 指 向 指 向 一 个 DWORD 数 值 , 该 数 值 返 回 实 际 写 入 的 字 节 数LPDWORD lpNumberOfBytesWritten,/ 重 叠 操 作 时 , 该 参 数 指 向 一 个 OVERLAPPED 结 构 ,/ 同 步 操 作 时 , 该 参 数 为 NULL。LPOVERLA

35、PPED lpOverlapped );在 用 ReadFile 和 WriteFile 读 写 串 口 时 , 既 可 以 同 步 执 行 , 也 可 以 重 叠 执 行 。在 同 步 执 行 时 , 函 数 直 到 操 作 完 成 后 才 返 回 。 这 意 味 着 同 步 执 行 时 线 程 会 被 阻 塞 ,从 而 导 致 效 率 下 降 。 在 重 叠 执 行 时 , 即 使 操 作 还 未 完 成 , 这 两 个 函 数 也 会 立 即 返 回 ,费 时 的 I/O 操 作 在 后 台 进 行 。ReadFile 和 WriteFile 函 数 是 同 步 还 是 异 步 由 Cr

36、eateFile 函 数 决 定 , 如 果 在调 用 CreateFile 创 建 句 柄 时 指 定 了 FILE_FLAG_OVERLAPPED 标 志 , 那 么 调 用ReadFile 和 WriteFile 对 该 句 柄 进 行 的 操 作 就 应 该 是 重 叠 的 ; 如 果 未 指 定 重 叠 标 志 ,则 读 写 操 作 应 该 是 同 步 的 。 ReadFile 和 WriteFile 函 数 的 同 步 或 者 异 步 应 该 和CreateFile 函 数 相 一 致 。ReadFile 函 数 只 要 在 串 口 输 入 缓 冲 区 中 读 入 指 定 数 量

37、的 字 符 , 就 算 完 成 操 作 。而 WriteFile 函 数 不 但 要 把 指 定 数 量 的 字 符 拷 入 到 输 出 缓 冲 区 , 而 且 要 等 这 些 字 符 从串 行 口 送 出 去 后 才 算 完 成 操 作 。如 果 操 作 成 功 , 这 两 个 函 数 都 返 回 TRUE。 需 要 注 意 的 是 , 当 ReadFile 和WriteFile 返 回 FALSE 时 , 不 一 定 就 是 操 作 失 败 , 线 程 应 该 调 用 GetLastError 函数 分 析 返 回 的 结 果 。 例 如 , 在 重 叠 操 作 时 如 果 操 作 还 未

38、 完 成 函 数 就 返 回 , 那 么 函 数就 返 回 FALSE, 而 且 GetLastError 函 数 返 回 ERROR_IO_PENDING。 这 说 明 重 叠操 作 还 未 完 成 。同 步 方 式 读 写 串 口 比 较 简 单 , 下 面 先 例 举 同 步 方 式 读 写 串 口 的 代 码 : /同 步 读 串 口char str100;DWORD wCount;/读 取 的 字 节 数BOOL bReadStat;bReadStat=ReadFile(hCom,str,100,if(!bReadStat)AfxMessageBox(“读 串 口 失 败 !“);r

39、eturn FALSE;return TRUE;/同 步 写 串 口char lpOutBuffer100;DWORD dwBytesWrite=100;COMSTAT ComStat;DWORD dwErrorFlags;BOOL bWriteStat;ClearCommError(hCom,bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,if(!bWriteStat)AfxMessageBox(“写 串 口 失 败 !“);PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR

40、|PURGE_RXCLEAR);在 重 叠 操 作 时 ,操 作 还 未 完 成 函 数 就 返 回 。 重 叠 I/O 非 常 灵 活 , 它 也 可 以 实 现 阻 塞 ( 例 如 我 们 可 以 设 置 一 定 要 读 取 到 一 个数 据 才 能 进 行 到 下 一 步 操 作 ) 。 有 两 种 方 法 可 以 等 待 操 作 完 成 : 一 种 方 法 是 用 象WaitForSingleObject 这 样 的 等 待 函 数 来 等 待 OVERLAPPED 结 构 的 hEvent 成 员 ;另 一 种 方 法 是 调 用 GetOverlappedResult 函 数 等

41、待 , 后 面 将 演 示 说 明 。下 面 我 们 先 简 单 说 一 下 OVERLAPPED 结 构 和 GetOverlappedResult 函 数 :OVERLAPPED 结 构OVERLAPPED 结 构 包 含 了 重 叠 I/O 的 一 些 信 息 , 定 义 如 下 : typedef struct _OVERLAPPED / o DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; HANDLE hEvent; OVERLAPPED;在 使 用 ReadFile 和 WriteFile 重

42、叠 操 作 时 , 线 程 需 要 创 建 OVERLAPPED 结构 以 供 这 两 个 函 数 使 用 。 线 程 通 过 OVERLAPPED 结 构 获 得 当 前 的 操 作 状 态 , 该 结构 最 重 要 的 成 员 是 hEvent。 hEvent 是 读 写 事 件 。 当 串 口 使 用 异 步 通 讯 时 , 函 数 返回 时 操 作 可 能 还 没 有 完 成 , 程 序 可 以 通 过 检 查 该 事 件 得 知 是 否 读 写 完 毕 。当 调 用 ReadFile, WriteFile 函 数 的 时 候 , 该 成 员 会 自 动 被 置 为 无 信 号 状 态

43、 ;当 重 叠 操 作 完 成 后 , 该 成 员 变 量 会 自 动 被 置 为 有 信 号 状 态 。 GetOverlappedResult 函 数BOOL GetOverlappedResult(HANDLE hFile, / 串 口 的 句 柄 / 指 向 重 叠 操 作 开 始 时 指 定 的 OVERLAPPED 结 构LPOVERLAPPED lpOverlapped,/ 指 向 一 个 32 位 变 量 , 该 变 量 的 值 返 回 实 际 读 写 操 作 传 输 的 字 节数 。LPDWORD lpNumberOfBytesTransferred,/ 该 参 数 用 于

44、指 定 函 数 是 否 一 直 等 到 重 叠 操 作 结 束 。/ 如 果 该 参 数 为 TRUE, 函 数 直 到 操 作 结 束 才 返 回 。/ 如 果 该 参 数 为 FALSE, 函 数 直 接 返 回 , 这 时 如 果 操 作 没 有 完 成 ,/ 通 过 调 用 GetLastError()函 数 会 返 回ERROR_IO_INCOMPLETE。BOOL bWait );该 函 数 返 回 重 叠 操 作 的 结 果 , 用 来 判 断 异 步 操 作 是 否 完 成 , 它 是 通 过 判 断OVERLAPPED 结 构 中 的 hEvent 是 否 被 置 位 来 实

45、 现 的 。异 步 读 串 口 的 示 例 代 码 : char lpInBuffer1024;DWORD dwBytesRead=1024;COMSTAT ComStat;DWORD dwErrorFlags;OVERLAPPED m_osRead;memset(m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);ClearCommError(hCom,dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);if(!dwBytesRead)return FALSE;BOOL bReadStatus

46、;bReadStatus=ReadFile(hCom,lpInBuffer,dwBytesRead,if(!bReadStatus) /如 果 ReadFile 函 数 返 回 FALSEif(GetLastError()=ERROR_IO_PENDING)/GetLastError()函 数 返 回 ERROR_IO_PENDING,表 明 串 口 正 在 进行 读 操 作WaitForSingleObject(m_osRead.hEvent,2000);/使 用 WaitForSingleObject 函 数 等 待 , 直 到 读 操 作 完成 或 延 时 已 达 到 2 秒 钟/当 串

47、 口 读 操 作 进 行 完 毕 后 , m_osRead 的 hEvent 事 件会 变 为 有 信 号PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);return dwBytesRead;return 0;PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);return dwBytesRead;对 以 上 代 码 再 作 简 要 说 明 : 在 使 用 ReadFile 函 数 进 行 读 操 作 前

48、 , 应 先 使 用ClearCommError 函 数 清 除 错 误 。 ClearCommError 函 数 的 原 型 如 下 : BOOL ClearCommError(HANDLE hFile, / 串 口 句 柄LPDWORD lpErrors, / 指 向 接 收 错 误 码 的 变 量LPCOMSTAT lpStat / 指 向 通 讯 状 态 缓 冲 区);该 函 数 获 得 通 信 错 误 并 报 告 串 口 的 当 前 状 态 , 同 时 , 该 函 数 清 除 串 口 的 错 误 标 志 以便 继 续 输 入 、 输 出 操 作 。参 数 lpStat 指 向 一 个

49、 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 recd DWORD

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报