位掩码(bitmask)在windows 串口事件驱动中的应用
最近在学习Windows串口通信,以事件驱动模式开发相关应用时,肯定会用到以下几个函数:
SetCommMask(HANDLE hComm, DWORD dwEvtMask);
GetCommMask(HANDLE hComm, LPDWORD lpEvtMask);
WaitCommEvent(HANDLE hComm, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
这几个函数的使用我就不再废话了,大家查MSDN就OK了。 我要说的重点是这几个函数应用了位掩码的方法来进行条件分支处理,非常自然,高效。无论对人 还是 对于机器来讲,都很优美。 非常值得我们在自己的工程实践中灵活运用。
其中的核心参数--需要捕获的事件代码,我们称其为“事件掩码”,用变量 dwEvtMask表示, 定义为16位长度,其可选值如下表所列。
英文单词或缩写的标识符常量,非常方便程序员理解,而其一一对应的十六进制常量值也早已在系统里预定义好了,各位直接使用意义直观的字符串常量就OK了。
Value | Meaning |
---|---|
EV_BREAK |
A break was detected on input. |
EV_CTS |
The CTS (clear-to-send) signal changed state. |
EV_DSR |
The DSR (data-set-ready) signal changed state. |
EV_ERR |
A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY. |
EV_RING |
A ring indicator was detected. |
EV_RLSD |
The RLSD (receive-line-signal-detect) signal changed state. |
EV_RXCHAR |
A character was received and placed in the input buffer. |
EV_RXFLAG |
The event character was received and placed in the input buffer. The event character is specified in the device'sDCB structure, which is applied to a serial port by using theSetCommState function. |
EV_TXEMPTY |
The last character in the output buffer was sent. |
这个被定义为16位长度的事件掩码变量,是我们这里要讨论的主角。 在我理解了Windows 在这里使用位掩码的机制之后,我建议你可以把它想象成一个由16盏信号灯排成一排所构成的一个信号灯箱,每盏灯只有开和关两种状态。
接下来我们再来看事件列表里的事件代码的Value,就是那个 0x开头的十六进制数,我们将它以二进制完全展开,如下所示:
事件代码 | 二进制表示 |
EV_BREAK |
0000 0000 0100 0000 |
EV_CTS |
0000 0000 0000 1000 |
EV_DSR |
0000 0000 0001 0000 |
EV_ERR |
0000 0000 1000 0000 |
EV_RING |
0000 0001 0000 0000 |
EV_RLSD |
0000 0000 0010 0000 |
EV_RXCHAR |
0000 0000 0000 0001 |
EV_RXFLAG |
0000 0000 0000 0010 |
EV_TXEMPTY |
0000 0000 0000 0100 |
秘密就在这里了。你有没有发现所有事件掩码值,要么是“1”,要么是2的正整数次幂,这样设计的结果就是,任何一个事件的掩码值的二进制表示里,“1”只出现一次,而所有九个事件的掩码值的二进制表示,同一位的纵向每一列里,“1”最多只出现一次!
现在我们对全部事件的二进制码进行位操作求 “|”,这有没有让你想到点什么?没错,就是当初我们设置要关注事件时,如果有两个或两个以上事件需要关注时,事件代码之间用的就是 "|" 操作。”|“ 操作之后,我们得到 “0000 0001 1111 1111”。这里一共九个”1“,而事件也正好是九个,不同位置上的”1“ 对应着不同的事件,这就是位掩码的意义所在。
/*小隐喻:刚才我说可以把事件掩码变量 dwEvtMask 想象成由十六个信号灯排成一排所组成的信号灯箱,我们每关注一个事件,就相当于接通对应信号灯的线路,但仅仅只是接通线路,还没有拉闸通电,当我们关注的事件真的发生了,那对应信号灯就会拉闸通电了。*/
接下来我们回到代码层面,在设置事件掩码时,如果我只关注一个事件,比如我只关注 “输入缓冲区收到了一个字符” 这么一个事件,那么
SetCommMask( hCom1, EV_RXCHAR); //此时事件掩码变量 dwEvtMask 的值实际上是”0“ ,但相应位置上的信号灯的线路已经接通,我们就用 ”0000 0000 0000 000?“ 来表示这种状态
如果我要关注两个事件,比如:
SetCommMask( hCom1, EV_RXCHAR | EV_ERR); //此时事件掩码变量 dwEvtMask 的值实际上是”0“,但有两盏信号灯的线路已接通,我们用 ”0000 0000 ?000 000?“来表示
那么三个,四个....哪怕全部九个事件都关注上,也是如此操作,如下:
SetCommMask( hCom1, EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY);
//此时事件掩码变量 dwEvtMask 的值仍是”0“,但九盏信号灯的线路都已接通,灯箱的状态为 ”0000 000? ???? ????“
当然我们也可以设置个灯箱指针,这样操作起来方便点:
DWORD *lpdwEvtMask = (EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY);
然后,我们启动监视功能:
WaitCommEvent(hCom1, lpdwEvtMask, NULL); //为聚焦今天的主题,这里暂不讨论重叠方式
一旦 事件掩码 变量里所罗列的事件中有任何一个或两个/三个...九个 事件发生,则其位掩码值将被填写进 dwEvtMask,即相应位被置1 (此动作由系统完成),在我的隐喻里,则是对应的信号灯通电点亮了。 当然,代码里是没有什么信号灯和可见光的(但是有智慧之光,呵呵),还是需要靠代码来说话。
SetCommMask( hCom1, EV_RXCHAR | EV_ERR); //假设我们现在关注两个事件
...
if ( WaitCommEvent(hCom1, lpdwEvtMask, NULL) ) //如果条件为真,则说明有关注的事件发生了,可能是一个,也可能是两个关注的事件都发生了,所以需要进一步鉴别
{
if ( dwEvtMask & EV_RXCHAR ) //如果EV_RXCHAR事件发生了,则dwEvtMask相应位被置”1“,条件运算的结果就是EV_RXCHAR事件的掩码值,既非零,又明确指出了是哪个事件
{
... //响应 EV_RXCHAR 事件
}
if ( dwEvtMask & EV_ERR )
{
... //响应 EV_ERR 事件
}
}
else
... //处理错误
这里的条件判断,体现出了运用位掩码的优势,其通过位运算就完成了事件筛选,代码阅读起来清晰易懂,而机器执行起来又绝对的高速度和高效率,所以我说这样的设计非常优美。
实际上,弄懂了这些之后,我们也完全可以在自己的代码实践中灵活运用 位掩码,从而使代码简洁,高效,优美。
延伸阅读:
http://blog.csdn.net/qsir/article/details/72457305
http://www.cnblogs.com/zyl910/archive/2012/03/12/noifopex1.html
位掩码(bitmask)在windows 串口事件驱动中的应用相关推荐
- java 位掩码_Java位掩码控制权限与()或(|)非(~)、的介绍
1. java 位掩码 java 位掩码,在java开发中很少有场景会用到掩码,但是当系统中需要判断某个对象是否有 某些权限时,可以通过位掩码来做. 位掩码 主要通过位运算,例如与(&).非( ...
- 上传文件转换html异常,JS 文件互转、10 个 HTML 文件上传技巧、Web 用户体验设计提升指南、奇怪的知识——位掩码 | 思否技术周刊...
上传文件功能可以说是项目经常出现的需求.从在社交媒体上上传照片到在求职网站上发布简历,文件上传无处不在.在本文中,我们将讨论 HTML文件上传支持的10种用法,希望对你有用. 1. 单文件上传 我们可 ...
- Java位运算在程序设计中的使用:位掩码(BitMask)
2019独角兽企业重金招聘Python工程师标准>>> Permission public class Permission {// 是否允许查询private boolean al ...
- 位掩码(BitMask)
位运算在实际开发中用得很少,主要原因还是它对于不熟悉的人不好读不好懂不好计算,如果不经常实践会生疏.但它的优点自然是计算快,代码更少.在某些地方它的优势会更加明显比如如下代码(http://xxgbl ...
- php获取掩码,如何在PHP中实现位掩码?
这很简单.首先一点代码演示如何实现.如果你不明白这个代码是做什么或它的工作原理,请随时在评论中提出其他问题: const FLAG_1 = 0b0001; // 1 const FLAG_2 = 0b ...
- JAVA中FC什么意思_java – 位掩码的规则是什么?像0xFF vs. 0xFC
我正在制作一个创建程序生成的地牢的游戏,我找到了一个使用位掩码来检索房间号和门类型等内容的例子. 在该示例中,他使用位掩码从每个图块的整数中提取细节.并且整数被这样分解 0xLLSDRRET L - ...
- Windows串口通信有关的MSComm控件
问题描述:一般单片机.ARM.FPGA一类的板子基本都会带有RS232串口,因为协议简单,而且成熟,有许多现成的东西可以借鉴使用.在上位机通过串口获取下位机传来的信息或数据,Windows下一般有(1 ...
- windows串口通信函数API
windows串口通讯主要函数 先列个目录表 1.CreateFile - 打开串口: 2.SetupComm-初始化一个指定的通信设备的通信参数 3.ReadFile - 读数据: 4.WriteF ...
- ipv6的127位掩码如何表示_子网掩码
子网掩码(subnet mask)又叫网络掩码.地址掩码.子网络遮罩,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码.子网掩码不能单独存在,它必须结合IP地 ...
最新文章
- java使用Jxl和Poi读写Excel
- 多视图几何总结——摄像机模型
- Windows各种计时器
- php按时间分组的sql语句,(SQL语句)按指定时间段分组统计
- python 硬件模拟_如何编写一个硬件模拟器?
- 数据:比特币和以太坊的证券产品规模已超过百亿美元
- Facebook 真的「非死不可」吗?
- 用*号打印直角三角形(正反)
- Maven教程:tutorialspoint-maven
- ML.NET 发布0.11版本:.NET中的机器学习,具有TensorFlow和ONNX的新功能
- 使用Confluence如何输出一份结构清晰 可读性高的测试文档?
- 【RWM】基于matlab路由无线传感器网络模拟随机路点运动模型【含Matlab源码 1565期】
- High Score
- mysql按时间查询的优化_Mysql根据时间查询日期的优化技巧
- 信号完整性(SI)电源完整性(PI)学习笔记(二十七)S参数在信号完整性中的应用(二)
- IOS开发入门(6)-自动布局(1)
- 知乎:月薪2~3万,码农怎样度过一天
- java实现微信退款
- 什么是多态?实现多态的机制是什么?
- ERP和SAP是什么意思?(转载)