3 串口状态

有两种获取通信端口状态的方法。第一种方法是设置事件掩码,当指定事件发生时应用程序会收到通知。SetCommMask函数用于设置事件掩码,WaitCommEvent用于等待指定的事件发生。它们与16位Windows中的SetCommEventMaskEnableCommNotification类似,只是它们不发送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 setting 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 setting communications mask      
       return FALSE;
   if (!WaitCommEvent(hComm, &dwCommEvent, NULL))
       // An error occurred waiting for the event.
       return FALSE;
   else
       // Event has occurred.
       return TRUE;

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

#define STATUS_CHECK_TIMEOUT      500   // Milliseconds

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 setting 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;
            else
               // error in WaitCommEvent; abort
               break;
         }
         else
            // 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.
             case 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.
                 else
                    // 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;
             case 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.
                CloseHandle(osStatus.hEvent);
                return 0;
         }
      }
   }
   CloseHandle(osStatus.hEvent);

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

Win32 串口编程(二)相关推荐

  1. Linux 串口编程二 深入了解 termios

    前言 这一系列串口编程重点在应用层编程,但是在讲解原理与相关概念时需要对驱动框架有个基础的认识.如果只是浅尝辄止,以后在遇到串口驱动与应用层程序调试难免遇到瓶颈.关于 tty驱动架构参见我的其他博客: ...

  2. Win32 串口编程(三)

    3.2 警告 使用EV_RXCHAR标志可以在每个字节到达端口时通知线程.与ReadFile配合使用,可以让程序在数据到达接收缓冲区后立即被读取:这与提交读取操作请求,然后等待数据到达是不同的.这对于 ...

  3. Win32 串口编程(一)

    翻译自:ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.WIN32COM.v10.en/dnfiles/html/msdn_serial.htm 老外写的文章, ...

  4. Win32 串口编程笔记1

    .打开和关闭串口 在Win32中,串口是作为文件处理的,使用CreateFile()函数可以打开串口,进行读写访问操作.CreateFile()返回串口句柄,可以在以后的端口操作中使用.关闭端口使用C ...

  5. Win32 串口编程(四)

    7 通信超时 通信超时是影响读写操作的另一个重要方面.如果操作所用时间大于超时值,则操作完成,ReadFile.WriteFile.GetOverlappedResule或者WaitForSingle ...

  6. POSIX 串口编程指南

    介绍 POSIX 串口编程指南将教会你在你的 UNIX 工作站或者 PC 上面如何成功.有效以及可移植性的对串口编程.每一章提供了使用 POSIX 终端控制函数的编程例程,可以基本不经修改地工作在 I ...

  7. Linux 串口编程四 串口设备程序开发

    Linux 串口编程和程序相对来说是很简单的,之所以用博客连载来展示,主要是想在学会使用的基础上掌握相关背景,原理以及注意事项.相信在遇到问题的时候,我们就不会对于技术的概念和 API 的使用浅尝辄止 ...

  8. Linux 串口编程三 使用termios与API进行串口程序开发

    在 termios 结构体以及内部终端控制标志中,并非所有的参数对于实际的物理串口都是有效的,在使用过程中也不需要对于所有标志的作用都有所理解.事实上,快速掌握一项技术的核心点也是一种学习能力.对于使 ...

  9. Linux 串口编程一 一些背景

    在大部分讲解 Linux 编程书籍的时候会发现没有单独的串口编程章节,实际上串口编程已经被概括在了"终端"或者"终端IO"章节里面.在上一篇博客中对经常出现的几 ...

最新文章

  1. 润乾报表新功能静态页面和report4包分离
  2. 2017年计算机应用题库,2017年自学考试管理系统中计算机应用题库精选试题6
  3. Comcast在美国境内遭遇大面积宕机和连接中断问题
  4. 如何毕业后继续白嫖知网
  5. 利用xcode6做出牛的一逼的计算器
  6. 序列输出ZOJ1108 FatMouse's Speed
  7. Django报错NameError: name ‘ListView‘ is not defined
  8. 改善CSS的10种最佳做法,帮助你从样式中获得最大的收益
  9. python new init_python的new与init
  10. 连载:面向对象的葵花宝典:思维、技能与实践(40) - DECORATOR模式
  11. 光伏补贴双轨制仍将延续
  12. 开源视频处理工具Shotcut的用法: 剪切、合并、增加背景音乐、添加字幕、 插入视频、图片转视频并加背景音乐、制作电子相册
  13. navicat 解析sql_Navicat使用详解
  14. 基于单片机的超声波测距仪的设计
  15. AndroidUI设计思想:程序易用性
  16. C语言之“输出100~200之间的素数”
  17. javascript思维导图大全
  18. Ubuntu18.04下的音频录制和编辑软件Ardour及QjackCtl(jackd gui)
  19. LiveNVR监控摄像头Onvif/RTSP视频流媒体服务平台概览负载信息实时展示取流中、播放中、录像中等使用数目说明
  20. Java截取视频生成Gif动图

热门文章

  1. bugly怎么读_高级功能
  2. opencv函数findcontours_OpenCV 中的轮廓应用
  3. 2020-07-07 内模原理(The Internal Mode Principle)
  4. java基础1--继承
  5. 9.JAVA之GUI编程列出指定目录内容
  6. Android 使用图片铺满某个区域
  7. MySQL is running but PID file is not found
  8. SQL中几个比较重要的系统表
  9. 一个时间日期转换格式的小功能(Oracle)
  10. 触发器初接触-同步两个表的指定字段