Java串口通信编程教程_hao

更新时间:2023-05-17 12:25:03 阅读: 评论:0

Win32 串口编程(一)(2009-08-16 16:28:13)
标签:串口 重叠i/o 
分类:Windows
翻译自:ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS./dnfiles/html/msdn_rial.htm
老外写的文章,虽比较全面,但很啰嗦,不如看各个函数的文档来得快。为方便以后查阅,列出本文涉及的主要函数如下:
CreateFile、ReadFile、WriteFile、GetOverlappedResult、WaitForSingleObject
SetCommMask、WaitCommEvent
王者英雄排名
ClearCommError、GetCommModemStatus、EscapeCommFunction
GetCommState、BuildCommDCB、SetCommState、SetCommTimeouts
此外,新浪的博客系统限制文章最大长度为40000字节,只好把这篇文章分成几部分了。
0 简介
本文仅关注在Windows NT和95间兼容的API。Windows 95支持Telephony API(TAPI),但Windows NT 3.x不支持TAPI,所以本文不讨论它。
本文的示例程序MTTTY(Multithreaded TTY)使用了三个线程:一个进行内存管理的界面线程;控制所有写入操作的写入者线程;读取数据和处理端口状态改变的读取/状态线程。示例采用了一些不同的堆来进行内存管理;还大量使用了同步方法来进行线程间通信。
1 打开端口
使用CreateFile函数打开端口。打开端口时有两种方法:重叠的和非重叠的。下列代码片段以重叠方式打开端口:
 
HANDLE hComm;
hComm = CreateFile( gszPort, 
                    GENERIC_READ | GENERIC_WRITE, 
                    0, 
                    0, 
                    OPEN_EXISTING,
                    FILE_FLAG_OVERLAPPED,
                    0);
if (hComm == INVALID_HANDLE_VALUE)
   // error opening port; abort
 
 Win32 串口编程(二)(2009-08-16 16:39:32)
标签:串口 重叠i/o it 
分类:Windows
3 串口状态
有两种获取通信端口状态的方法。第一种方法是设置事件掩码,当指定事件发生时应用程序会收到通知。SetCommMask函数用于设置事件掩码,WaitCommEvent用于等待指定的事件发生。它们与16位Windows中的SetCommEventMask和EnableCommNotification类似,只是它们不发送WM_COMMNOTIFY消息。第二种方法是不时地调用另一些状态函数来获取通信端口的状态。当然,轮询是低效的,不建议使用。
3.1 通信事件
通信事件在使用通信端口时可能随时发生。接收通信事件需要两个步骤:
用SetCommMask设定需要接收通知的事件
用WaitCommEvent提交状态检查请求,请求可以是重叠的或者非重叠的,与读写操作一样。
下面是使用SetCommMask的示例:
化妆技巧
DWORD dwStoredFlags;
dwStoredFlags = EV_BREAK | EV_CTS   | EV_DSR | EV_ERR | EV_RING |               
                EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;
if (!SetCommMask(hComm, dwStoredFlags))   
  // error tting communications mask
 
 

下表描述了每种事件类型。
 
事件标志
描述
EV_BREAK
检测到输入中的break
EV_CTS
CTS(Clear To Send)信号状态改变。要取得CTS线路状态,应使用GetCommModemStatus函数。
EV_DSR
DSR(Data Set Ready)信号状态改变。要取得DSR线路状态,应使用GetCommModemStatus函数。
EV_ERR
某线路状态错误发生。线路状态错误包括CE_FRAME、CE_OVERRUN和CE_RXPARITY。要取得具体错误种类,需调用ClearCommError函数。
EV_RING
检测到振铃指示
EV_RLSD
RLSD(Receive Line Signal Detect)信号状态改变。要取得RLSD线路状态,需调用GetCommModemStatus函数。注意,RLSD通常被称作CD(carrier detect)。
EV_RXCHAR
接收到一个字符并且已放入输入缓冲区。请参考下面的“警告”节对此标志的详细讨论。
EV_RXFLAG
接收到一个事件字符并且已放入输入缓冲区。事件字符由下文讨论的DCB结构EvtChar字段指定。下面的“警告”节也讨论了这个标志。
EV_TXEMPTY
输出缓冲区中最后一个字符被发送到串口设备了。如果使用硬件缓冲区,此标志仅表示所有数据已经发送到硬件了。如果不与设备驱动交互,是无法确定硬件缓冲区空的。
 
指定事件掩码后,使用WaitCommEvent函数检测事件发生。如果以非重叠方式打开端口,则WaitCommEvent不需要OVERLAPPED结构体,函数阻塞调用线程直到某事件发生。如果没有事件发生,调用线程将无限阻塞。
下面的代码片段展示了如何在以非重叠方式打开的端口上等待EV_RING事件。
   DWORD dwCommEvent;
工程管理学报   if (!SetCommMask(hComm, EV_RING))     
       // Error tting communications mask     
      return FALSE;
   if (!WaitCommEvent(hComm, &dwCommEvent, NULL))
      // An error occurred waiting for the event.
       return FALSE;
  el
      // Event has occurred.
      return TRUE;

 
 
 
 

如果没有事件发生,上面的代码将无限阻塞调用线程。解决方法是以重叠方式打开端口,用下面的方式等待状态事件:
 
  #define STATUS_CHECK_TIMEOUT      500   // Milliconds

   DWORD      dwRes;
   DWORD      dwCommEvent;
   DWORD      dwStoredFlags;
   BOOL      fWaitingOnStat = FALSE;
   OVERLAPPED osStatus = {0};
   dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |\
                  EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;
   if (!SetCommMask(comHandle, dwStoredFlags))
      // error tting communications mask; abort
      return 0;
   osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
   if (osStatus.hEvent == NULL)
于敏的事迹      // error creating event; abort
      return 0;
   for ( ; ; ) {
      // Issue a status event check if one hasn't been issued already.
      if (!fWaitingOnStat) {
         if (!WaitCommEvent(hComm, &dwCommEvent, &osStatus)) {
            if (GetLastError() == ERROR_IO_PENDING)
               bWaitingOnStatusHandle = TRUE;
            el
               // error in WaitCommEvent; abort
               break;
         }月子饭
         el
            // WaitCommEvent returned immediately.
            // Deal with status event as appropriate.
            ReportStatusEvent(dwCommEvent); 
      }
      // Check on overlapped operation.
      if (fWaitingOnStat) {
         // Wait a little while for an event to occur.
         dwRes = WaitForSingleObject(osStatus.hEvent, STATUS_CHECK_TIMEOUT);
         switch(dwRes)
         {
真情满天下             // Event occurred.
             ca WAIT_OBJECT_0: 
五行属土的行业                 if (!GetOverlappedResult(hComm, &osStatus, &dwOvRes, FALSE))
                    // An error occurred in the overlapped operation;
                    // call GetLastError to find out what it was
                    // and abort if it is fatal.
                 el
                    // Status event is stored in the event flag
                    // specified in the original WaitCommEvent call.
                    // Deal with the status event as appropriate.
                    ReportStatusEvent(dwCommEvent);
                 // Set fWaitingOnStat flag to indicate that a new
                 // WaitCommEvent is to be issued.
                 fWaitingOnStat = FALSE;
                 break;
             ca WAIT_TIMEOUT:
                 // Operation isn't complete yet. fWaitingOnStatusHandle flag 
                 // isn't changed since I'll loop back around and I don't want
                 // to issue another WaitCommEvent until the first one finishes.
                 //那的组词
                 // This is a good time to do some background work.
                DoBackgroundWork();
                 break;                       
             default:
                 // Error in the WaitForSingleObject; abort
                 // This indicates a problem with the OVERLAPPED structure's
                 // event handle.
                CloHandle(osStatus.hEvent);
                return 0;
         }
      }
   }
   CloHandle(osStatus.hEvent);

上面的代码片段与重叠读取操作的代码非常相似。实际上,MTTTY使用WaitForMultipleObjects在同一个线程中等待读取完成或者状态改变事件发生。SetCommMask和WaitCommEvent有两种很有意思的边际效应。第一,如果以非重叠方式打开通信端口,WaitCommEvent将阻塞直到某事件发生。如果其他线程调用SetCommMask设置新的事件掩码,则线程将阻塞在SetCommMask调用上,原因是第一个线程的WaitCommEvent调用仍在执行中。SetCommMask将一直阻塞调用线程,直到第一个线程的WaitCommEvent调用返回。这种边际效应对于以非重叠方式打开的端口是通用的。如果某线程阻塞在任何通信函数上,则第二个线程对任何通信函数的调用都将阻塞,直到第一个线程的函数调用返回。第二种边际效应是关于以重叠方式打开的端口的。如果使用SetCommMask设置新的事件掩码,则未决的WaitCommEvent调用将成功完成,导致调用完成的事件掩码将是NULL。
 
 
 
 






去掉参数中的FILE_FLAG_OVERLAPPED就是非重叠操作方式了。用CreateFile打开通信端口时,有下列限制:
fdwShareMode 必须是0。通信端口不能像文件那样被共享。要共享通信端口,需要使用句柄继承或者复制操作。
fdwCreate 必须指定 OPEN_EXISTING 标志。
hTemplateFile 参数必须是 NULL。
端口名通常是COM1、COM2、COM3和COM4。Win32 API不提供确定系统中有哪些端口可用的机制。Windows NT和Windows 95跟踪系统已安装端口的方法是不同的,所以不太可能提供兼容的确定可用端口的方法。某些系统可能有多于4个端口,而传统的通信端口最大个数是4。硬件厂商和串口驱动编写者可以自由地为端口命名。所以,程序最好可以让用户指定要使用的端口名字。如果端口不存在,则试图打开端口时会返回ERROR_FILE_NOT_FOUND错误,这时应该提示用户端口不可用。
2 读写操作
通信端口的读写操作与文件I/O操作非常相似,它们使用同样的函数。Win32的I/O操作可分为两种:重叠(overlapped)的和非重叠的(nonoverlapped)。平台SDK文档分别使用异步(asynchronous)和同步(synchronous)来表示这两种I/O方式。
很多开发者都熟悉非重叠I/O,因为它就是传统的I/O方式:函数返回时,所请求的操作已经完成。然而在重叠I/O的情况下,系统则可能在操作还没有完成的情形下立即返回,随后才通知调用者操作完成。程序可以在发起I/O请求和请求被完成之间进行一些后台工作。
2.1 非重叠I/O
非重叠I/O的工作方式很简单:I/O操作进行时,调用线程被阻塞;操作完成后,函数返回,调用线程可以继续执行。在多线程应用中,这种I/O方式很有用:一个线程阻塞在某I/O操作上时,其他线程可以继续工作。应用程序应该保证对端口的串行访问。某个线程阻塞在等待某I/O操作上时,其他线程后续的通信API调用也都将阻塞。比如说,一个线程在等待ReadFile调用返回时,另一个线程的WriteFile函数调用将阻塞。

本文发布于:2023-05-17 12:25:03,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/908085.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:端口   线程   事件   调用   状态   重叠
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图