logo资料库

Win32串口通信-Serial Communications In Win32(修订版).pdf

第1页 / 共29页
第2页 / 共29页
第3页 / 共29页
第4页 / 共29页
第5页 / 共29页
第6页 / 共29页
第7页 / 共29页
第8页 / 共29页
资料共29页,剩余部分请下载后查看
WIN32 串口通信 微软技术文档 摘要 学习 Win32 中的串口通信和 16 位 Windows 操作系统中的串口通信有很大的不同。 这篇文章假设读者已经熟悉 Win32 下多线程和同步的基本原理。 Zcube zcube@qq.com
目录 ·i· WIN32 中的串行通信 ........................................................................................................................................ 1 综述 ............................................................................................................................................................... 1 引言 ............................................................................................................................................................... 1 打开串口 ...................................................................................................................................................... 2 读和写 ........................................................................................................................................................... 3 非重叠 I/O ............................................................................................................................................ 3 重叠 I/O ................................................................................................................................................ 3 读 ........................................................................................................................................................... 4 写 ........................................................................................................................................................... 6 串行状态 ...................................................................................................................................................... 9 通信事件 .............................................................................................................................................. 9 告诫..................................................................................................................................................... 12 错误处理和通信状态 ....................................................................................................................... 14 调制解调器状态(又名:线状态) .............................................................................................. 16 扩展的功能 ........................................................................................................................................ 16 串行设置 .................................................................................................................................................... 17 DCB 设置 ........................................................................................................................................... 17 流控制 ................................................................................................................................................ 20 硬件流控制 ........................................................................................................................................ 20 软件流控制 ........................................................................................................................................ 21 通信超时 ............................................................................................................................................ 23 小结 ............................................................................................................................................................. 25 参考文献 .................................................................................................................................................... 26
·1· WIN32 中的串行通信 艾伦 戴夫 微软 Windows 开发者支持中心 1995/12/11 应用于:  Microsoft® Win32®  Microsoft Windows® 摘要:学习 Win32 中的串口通信和 16 位 Windows 操作系统中的串口通信有很大的不同。这篇文章 假设读者已经熟悉 Win32 下多线程和同步的基本原理。另外,如果对 Win32 中的 heap 功能如果有基础 的了解,将使读者在完全理解这篇文章中提到的多线程 TTY(MTTTY)例子的内存管理方法上是很有 用的。 综述 Win32 中的串口通信和 16 位 Windows 中的串口通信有显著的不同。那些熟悉 16 位串口通信函数的 开发人员将不得不重新学习许多系统部分的知识,以便能编写正确的串口通信程序。这篇文章将帮助实 现这个目标。那些不熟悉串口通信的人员将发现这篇文章会为他们以后研究发展奠定坚实的基础。 这篇文章假设读者已经熟悉 Win32 下多线程和同步的基本原理。另外,如果对 Win32 中的 heap 功 能如果有基础的了解,将使读者在完全理解这篇文章中提到的 MTTTY 例子的内存管理方法上是很有用 的。 关于这些函数的更多信息,请查阅平台 SDK 文档:微软 Win32 知识库或微软开发者联机文库。虽 然那些控制用户界面特性的应用程序接口(APIs)和对话框在这里并不讨论,但是对完全理解这篇文章 所提供的例程还是很有用的。不熟悉一般的 Windows 编程的读者在开始处理串行通信前首先应该学习 一些 Windows 编程基础。换句话说,冒失地潜水前先沾湿你的脚。 引言 这篇文章主要介绍应用程序接口(APIs)和微软 Windows NT 以及 Windows 95 所兼容的方法。因 此,只讨论在 NT 和 95 这两个平台上都被支持的 APIs。Windows 95 支持 Win32 电话 API(TAPI),但
·2· 是 Windows NT 3.x 却不支持。因此,这里不对 TAPI 进行讨论。然而,TAPI 值得一提的时,它在调制 解调器的连接和调用控制上是非常好的工具。如果一个应用程序产品涉及调制解调器工作和电话拨号, 那么利用 TAPI 接口可以实现这些功能。它允许和用户可能有的 TAPI 程序实现无缝结合。此外,这篇 文章也不讨论 Win32 中的一些配置函数,像 GetCommProperties。 这篇文章包含的例子,MTTTY:多线程 TTY(4918.exe),实现了许多这里所要讨论的功能。在它 的实现中使用了 3 个线程:一个用户界面线程实现内存管理、一个写线程实现控制所有的写操作、还有 一个读/状态线程实现读数据和处理端口上发生改变的状态。该例子采用一些不同的数据堆实现内存管理。 它也广泛使用同步方法促进线程之间的通信。 打开串口 使用 CreateFile 函数可以打开一个通信端口。调用 CreateFile 打开通信端口有两种方式:重叠的和 非重叠的。下面是使用重叠方式打开一个通信资源的例子: HANDLE hComm; hComm = CreateFile(gszPort, GENERIC_READ | GENERIC_W RITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if (hComm == INVALID_HANDLE_VALUE) // 打开错误;使中止。 移除 CreateFile 中的 FILE_FLAG_OVERLAPPED 标志可指定为非重叠方式。下一章节将对重 叠和非重叠方式进行讨论 在 Win32 软件开发工具包(SDK)程序员参考手册(概述,窗口管理,系统服务)中规定,当打开 一个通信端口时候,调用 CreateFile 有如下要求:  fdwShareMode 必须为 0。通信端口不能像文件一样被共享。应用程序使用 TAPI 可以使用 TAPI 函数很容易实现两个应用程序之间的资源共享。对于 Win32 应用程序,不是使用 TAPI。处理 继承或副本需要共享通信端口。处理副本超出了本文的范围,请查阅 Win32 SDK 文档获取更多 信息。  fdwCreate 必须指定为 OPEN_EXISTING 标志。  hTemplateFile 必须是 NULL。 需要注意一件事,惯例上它们有四个端口分别为:COM1、COM2、COM3 和 COM4。Win32 API 没有提供任何途径去确定系统中存在的端口。Windows NT 和 Windows 95 在配置串口方面互相并不相同, 所以任何一种方法都不能确保对所有的 Win 32 平台都是可移植的。一些系统甚至有比惯例上的最大数 量四个端口还要多的端口。硬件厂商和串行设备驱动的作者可以用他们所喜欢的方式去自由命名端口。
·3· 为此,如果用户可以去指定他们想用的端口名是最好的选择。如果一个端口不存在,在企图打开这个端 口的时候一个错误(ERROR_FILE_NOT_FOUND)将会出现,应该警告用户这个端口是不可用的。 读和写 从通信端口读和写在 Win32 中极其类似于 Win32 中文件的输入/输出(I/O)。实际上,实现文件 I/O 的函数和用于串行 I/O 的函数是相同的。Win32 中的 I/O 可以通过两种方式被使用:重叠和非重叠。 在 Win32 SDK 文档中用异步和同步这样的术语去暗示这些 I/O 操作的类型。然而,这篇文章中将用重叠 和非重叠这样的术语。 非重叠 I/O 对于大多数开发者来说是熟悉的,因为这属于传统的 I/O 操作形式,当函数返回的时候 一个被请求的操作将被假设为已完成。就重叠 I/O 来说,即使操作没有完成系统也可以立刻返回给调用 者,当操作完成的时候将会用信号通知调用者。程序可以利用 I/O 请求和结束这段时间去执行一些“后 台”工作。 在 Win32 中和 16 位 Windows 中对串行通信端口的读和写有显著的不同。16 位 Windows 只有 ReadComm 和 WriteComm 函数。Win32 中的读写操作可能牵涉更多的函数和选择。这些问题在下文将 会被讨论。 非重叠 I/O 非重叠 I/O 非常简单,虽然它还有一些限制。一个操作的执行将导致调用它的线程被阻塞。一旦该 操作完成,函数返回,线程继续工作。这种类型的 I/O 对于多线程应用程序来说是非常有用的,因为当 I/O 操作的时候即使一个线程被阻塞,其它线程仍然可以执行工作。应用程序有责任正确无误的处理连 续的端口操作。如果一个线程被阻塞去等待 I/O 操作的完成,随后的其它线程如果调用一个通信 API 也 将可能被阻塞,直到最初的操作完成。例如,如果一个线程正在等待 ReadFile 函数返回,其它线程如 果调用 WriteFile 函数将会被阻塞。 在非重叠和重叠操作之间做出选择的诸多因素中,其中之一是要考虑到可移植性。重叠操作不是一 个好的选择,因为大多数操作系统并不支持它。然而大多数操作系统支持多线程,所以多线程的非重叠 I/O 操作从可移植性上面考虑的话是最好的选择。 重叠 I/O 重叠 I/O 不像非重叠 I/O 那样简单的,但是提供了更多的灵活性和效率。当一个端口打开的时候, 对于重叠操作来说,允许线程与此同时执行 I/O 操作和其它的工作,即使这个操作正处于不确定状态。 此外,重叠操作允许单线程发出许多不同的请求和执行后台工作,即使这个操作处于不确定状态。 对于单线程和多线程应用程序,在发出请求和得到结果之间必须产生一些同步性。一个线程将会被 阻塞,直到一个操作的结果变为有效的。重叠 I/O 的优势所在是允许一个线程在请求和完成之间去做一
·4· 些工作。如果没有工作可以被做,然后对于重叠 I/O 只有一种可能,就是它将允许为更好的用户提供响 应。 重叠 I/O 是 MTTTY 例子中所使用的一种操作类型。它创建一个线程来负责读取端口的数据和状态。 它也执行定期的后台工作。程序创建另外一个线程专门用来从端口写出数据。 注意:有时应用程序创建太多的线程,滥用多线程操作系统。虽然利用多线程可以解决很多困难的 问题,但是创建过多的线程在应用程序中并不是最有效的方式。在系统中线程没有进程紧张,但是仍然 会占用系统资源,像 CPU 时间和内存。如果一个应用程序创建过多的线程,可能对整个系统的性能产 生不利的影响。线程的一个更好的使用方式是对每个工作类型创建一个不同的请求队列,有一个工作者 线程通过发出一个 I/O 请求使其进入请求队列。上述方法将会被这篇文章中所提到的 MTTTY 这个例子 用到。 一个重叠 I/O 操作包含两部分:创建操作和检测是否完成。创建操作必须建立一个 OVERLAPPED 结构体,为同步创建一个手工重置事件,然后在调用特定的函数(ReadFile 或 WriteFile)。I/O 操作可 能也可能不会立即的完成。对于一个程序来说,如果假定一个重叠操作请求总是产生一个重叠操作是错 误的。如果一个操作完成后,应用程序需要准备继续正常地运行。重叠操作的第二部分是检测它是否完 成。检测操作是否完成包含等待事件处理,检查重叠结果和处理数据。有很多工作牵涉到重叠操作的原 因是存在很多故障点。如果一个非重叠操作失败了,函数只是会返回一个错误返回的结果。如果一个重 叠操作失败了,它可能在创建操作时候失败或是使操作处于等待状态。你也可能有一个超时操作或只是 一个超时去等待操作完成的信号。 读 ReadFile 函数将产生一个读的操作。ReadFileEx 也产生一个读操作,但是因为它在 Windows 95 上 是不可用的,所以在这篇文章中不对它做讨论。这里的代码段详细说明了怎样产生一个读操作。注意, 如果 ReadFile 函数返回 TRUE,它的功能是将调用一个函数去处理数据。如果操作变成了重叠方式,这 个处理数据的函数也是一样的。注意在代码段中定义的 fWaitingOnRead 标记变量,用它来指明一个读 操作是否为重叠的。它通常用来防止在一个读操作尚未完成的时候又重新创建一个新的读操作。 DW ORD dwRead; BOOL fW aitingOnRead = FALSE; OVERLAPPED osReader = {0}; // 创建重叠事件。必须关闭以前存在的事件以避免句柄泄露。 osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (osReader.hEvent == NULL) // 创建重叠事件错误;使中止。 if (!fWaitingOnRead) { // 执行读操作 if (!ReadFile(hComm, lpBuf, READ_BUF_SIZE, &dwRead, &osReader)) { // 读操作是否处于等待状态?
} } if (GetLastError() != ERROR_IO_PENDING) // 通信错误;报告该错误。 else fWaitingOnRead = TRUE; else { // 完成读操作 HandleASuccessfulRead(lpBuf, dwRead); } ·5· 重 叠 操 作 的 第 二 部 分 是 检 测 它 是 否 完 成 。 OVERLAPPED 结 构 体 中 的 事 件 句 柄 会 被 传 递 到 WaitForSingleObject 函数中进行等待,直到对象被传递信号。一旦事件被传递信号,则代表操作完成 了。这并不意味着操作是被成功地完成,仅仅是完成而已。GetOverlappedResult 函数将报告操作的结 果。如果发生了错误,GetOverlappedResult 函数将返回 FALSE,GetLastError 函数将返回错误代码。 如果操作被成功的完成,GetOverlappedResult 将返回 TRUE。 注意:GetOverlappedResult 函数可以探测操作是否完成,也可以返回操作的失败状态。如果操作 没有完成,GetOverlappedResult 将返回 FALSE 且 GetLastError 函数将返回 ERROR_IO_INCOMPLETE。 此外,GetOverlappedResult 可能会被阻塞直到操作完成。实际上,重叠操作转变成非重叠操作可以通 过给 GetOverlappedResult 函数中的 bWait 参数传递 TRUE 来实现。 这里的代码段展示了一种检查一个重叠读操作是否完成的方法。注意下面的代码也调用的处理数据 函数和上面是相同的,该函数在操作完成后立即调用。也要注意使用的 fWaitingOnRead 标记,在这里 它用来控制是否执行检测代码,因为它只有在一个读操作尚未完成时候才应该被调用。 #define READ_TIMEOUT 500 // 毫秒 DW ORD dwRes; if (fWaitingOnRead) { dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT); switch(dwRes) { // 读操作完成。 case WAIT_OBJECT_0: if (!GetOverlappedResult(hComm, &osReader, &dwRead, FALSE)) // 通信错误;报告该错误。 else // 读操作成功地完成。 HandleASuccessfulRead(lpBuf, dwRead); // 重置标记变量,以便其它操作可以被执行。 fWaitingOnRead = FALSE; break;
分享到:
收藏