C# SerialPort自定义串口DCB
译自Change DCB fields from SerialPort instance C#
C# SerialPort自定义串口DCB
DCB(Device Control Block)在C++ 里面是用bitfield(位域)表示的,C#没有bitfield,但有一个枚举位标志。C#有自己的方法来设置怎么存取DCB,而且“SerialStream”里确实也有“SetDcbFlag”方法(该方法接收2个int参数)。在研究了.Net源码后,我创建了一组常量用来等效原来的DCB int字段和他们的新int代码,我暂时还没有整理出所有位标志,不过你可以在DCB文档里面查阅它们。因为这是一个Internal方法只对.Net内部程序集可见,所以我在获取该方法时用到了System.Reflection(反射)。
下面就是代码,整体上是一个.Net 2.0+SerialPort的扩展类。扩展类中有三个方法,SetField(string name, object value)方法用来设置所有不是以'f'开头的位,SetFlag(int Flag, int Value)方法用来处理以'f'开头的位(我提供了一个针对Flag参数的const列表),最后UpdateComm()方法用来在你更改DCB后刷新串口连接,它本来是SetField方法的一部分,但是如果设置DCB时每次都调用它,那花的时间就有点长了。
注意:
确保开启串口连接后,再使用这些方法。
用法:
SerialPort COM = new SerialPort("COM7");
COM.Open();
COM.DiscardInBuffer();
COM.DiscardOutBuffer();
COM.SetFlag(FBINARY, );
COM.SetFlag(FPARITY, );
COM.SetFlag(FDTRCONTROL, 0x00);
COM.SetFlag(FRTSCONTROL, 0x01);
COM.SetField("BaudRate", (UInt32));
COM.SetField("StopBits", (byte));
COM.SetField("ByteSize", (byte));
COM.SetField("Parity", (byte));
COM.SetField("XonChar", (byte)0x11);
COM.SetField("XoffChar", (byte)0x13);
COM.SetField("EvtChar", (byte)0x1A);
COM.SetField("XonLim", (ushort));
COM.SetField("XoffLim", (ushort));
COM.UpdateComm();
/* Do Stuff */
COM.Close();
常量:
internal const int FBINARY = ;
internal const int FPARITY = ;
internal const int FOUTXCTSFLOW = ;
internal const int FOUTXDSRFLOW = ;
internal const int FDTRCONTROL = ;
internal const int FDSRSENSITIVITY = ;
internal const int FTXCONTINUEONXOFF = ;
internal const int FOUTX = ;
internal const int FINX = ;
internal const int FERRORCHAR = ;
internal const int FNULL = ;
internal const int FRTSCONTROL = ;
internal const int FABORTONOERROR = ;
internal const int FDUMMY2 = ;
最后,扩展类
internal static class SerialPortExtensions
{
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void SetField(this SerialPort port, string field, object value)
{
if (port == null)
throw new NullReferenceException();
if (port.BaseStream == null)
throw new InvalidOperationException("Cannot change fields until after the port has been opened.");
try
{
object baseStream = port.BaseStream;
Type baseStreamType = baseStream.GetType();
FieldInfo dcbFieldInfo = baseStreamType.GetField("dcb", BindingFlags.NonPublic | BindingFlags.Instance);
object dcbValue = dcbFieldInfo.GetValue(baseStream);
Type dcbType = dcbValue.GetType();
dcbType.GetField(field).SetValue(dcbValue, value);
dcbFieldInfo.SetValue(baseStream, dcbValue);
}
catch (SecurityException) { throw; }
catch (OutOfMemoryException) { throw; }
catch (Win32Exception) { throw; }
catch (Exception)
{
throw;
}
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void SetFlag(this SerialPort port, int flag, int value)
{
object BaseStream = port.BaseStream;
Type SerialStream = BaseStream.GetType();
SerialStream.GetMethod("SetDcbFlag", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(BaseStream, new object[] { flag, value });
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void UpdateComm(this SerialPort port)
{
object baseStream = port.BaseStream;
Type baseStreamType = baseStream.GetType();
FieldInfo dcbFieldInfo = baseStreamType.GetField("dcb", BindingFlags.NonPublic | BindingFlags.Instance);
object dcbValue = dcbFieldInfo.GetValue(baseStream);
SafeFileHandle portFileHandle = (SafeFileHandle)baseStreamType.GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(baseStream);
IntPtr hGlobal = Marshal.AllocHGlobal(Marshal.SizeOf(dcbValue));
try
{
Marshal.StructureToPtr(dcbValue, hGlobal, false);
if (!SetCommState(portFileHandle, hGlobal))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
finally
{
if (hGlobal != IntPtr.Zero)
Marshal.FreeHGlobal(hGlobal);
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetCommState(SafeFileHandle hFile, IntPtr lpDCB);
}
Change DCB fields from SerialPort instance C
The DCB struct requires a C++ class known as a bitfield, which C# does not have, so instead they have a field called "Flags" stored as a UInt32.They have their own melarchy set up there as to how it's stored and read from, but they did put a method in the SerialStream called SetDcbFlag which accepts two ints.After digging through the .net source a bit, I managed to come up with a set of constants equating to the original DCB Fields and their new int code, I haven't yet made a list of values for these flags, but those can be easily found in the DCB Documentation.I used system.reflection to gain access to the method as it was an internal method only to be used by internal .NET source.
So here it is, the code, it's an extension class for the SerialPort class which is shipped stock with .NET 2.0+. My extension class adds three methods, SetField(string name, object value) which will set any of the fields that aren't prefixed with "f", SetFlag(int Flag, int Value) which will take care of those fields prefixed with "f" (I'll provide a list of constants for use with the Flag parameter), and finally UpdateComm() this will update the serial connection once you have changed all of your values, it was originally part of the SetField method, but it takes slightly longer to complete things if it's calling that every single time during initialization.
NOTE:
The serial port must be opened before using any of these methods!
Usage:
略
Constants:
略
And finally, the extension class:
略
PS:中文DCB结构详解表
MSDN的DCB文档和这个内容基本相同
| 成员 | 取值 | 说明 |
|---|---|---|
| DCBlength | DCB结构大小,即sizeof(DCB),在调用SetCommState来更新DCB前必须作设置 | |
| BaudRate | 指定当前采用的波特率,应与所连接的通讯设备相匹配 | |
| fBinary | 指定是否允许二进制模式。Win32 API不支持非二进制模式传输,应设置为true | |
| fParity | 指定奇偶校验是否允许,在为true时具体采用何种校验看Parity 设置 | |
| Parity | 指定端口数据传输的校验方法。以下是可取值及其意义: | |
| EVENPARITY | 偶校验(2) | |
| MARKPARITY | 标记校验,所发信息帧第9位恒为1(3) | |
| NOPARITY | 无校验(0) | |
| ODDPARITY | 奇校验(1) | |
| StopBits | 指定端口当前使用的停止位数,可取值: | |
| ONESTOPBIT | 1停止位(0) | |
| ONE5STOPBITS | 1.5停止位(1) | |
| TWOSTOPBITS | 2停止位(2) | |
| fErrorChar | 该值为TRUE,则用ErrorChar指定的字符代替奇偶校验错误的接收字符 | |
| ErrorChar | 指定ErrorChar字符(代替接收到的奇偶校验发生错误时的字节) | |
| EvtChar | 当接收到此字符时,会产生一个EV_RXFLAG事件,如果用SetCommMask函数中指定了EV_RXFLAG ,则可用WaitCommEvent 来监测该事件 | |
| EofChar | 指定用于标示数据结束的字符 | |
| fNull | 为TRUE时,接收时自动去掉空(0值)字节 | |
| fAbortOnError | 读写操作发生错误时是否取消操作。若设置为true,则当发生读写错误时,将取消所有读写操作(错误状态置为ERROR_IO_ABORTED),直到调用ClearCommError函数后才能重新进行通讯操作 | |
| fOutxCtsFlow | 是否监控CTS(clear-to-send)信号来做输出流控。当设置为true时:若CTS为低电平,则数据发送将被挂起,直至CTS变为高。CTS的信号一般由DCE(通常是一个Modem)来控制,而DTE(通常是计算机)发送数据时监测CTS信号。也就是说DCE通过把CTS置高来表明自己可以接收数据了 | |
| fRtsControl | 设置RTS (request-to-send)流控,若为0则缺省取值 RTS_CONTROL_HANDSHAKE。以下是可取值及其意义: | |
| RTS_CONTROL_DISABLE | 打开设备时置RTS信号为低电平,应用程序可通过调用EscapeCommFunction函数来改变RTS线电平状态 | |
| RTS_CONTROL_ENABLE | 打开设备时置RTS信号为高电平,应用程序可通过调用EscapeCommFunction函数来改变RTS线电平状态 | |
| RTS_CONTROL_HANDSHAKE | 允许RTS信号握手,此时应用程序不能调用EscapeCommFunction函数。当输入缓冲区已经有足够空间接收数据时,驱动程序置RTS为高以便允许DCE来发送;反之置RTS为低以阻止DCE发送数据。 | |
| RTS_CONTROL_TOGGLE | 有字节要发送时RTS变高,当所有缓冲字节已经被发送完毕后,RTS变低。此时应用程序不能调用EscapeCommFunction函数。该值在Windows 95系统被忽略 | |
| fOutxDsrFlow | 是否监控DSR (data-set-ready) 信号来做输出流控。当设置为true时:若DSR为低电平,则数据发送将被挂起,直至DSR变为高。DSR的信号一般由DCE来控制 | |
| fDtrControl | DTR (data-terminal-ready)流控,可取值如下: | |
| DTR_CONTROL_DISABLE | 打开设备时置DTR信号为低电平,应用程序可通过调用EscapeCommFunction函数来改变DTR线电平状态 | |
| DTR_CONTROL_ENABLE | 打开设备时置DTR信号为高电平,应用程序可通过调用EscapeCommFunction函数来改变DTR线电平状态 | |
| DTR_CONTROL_HANDSHAKE | 允许DTR信号握手,此时应用程序不能调用EscapeCommFunction函数 | |
| fDsrSensitivity | 通讯设备是否对DSR信号敏感。若设置为TRUE,则当DSR为低时将会忽略所有接收的字节 | |
| fTXContinueOnXoff | 当输入缓冲区满且驱动程序已发出XOFF字符时,是否停止发送。当为TRUE时,XOFF被发送后发送仍然会继续;为FALSE时,发送停止,直至输入缓冲区有XonLim字节的空余空间、驱动程序已发送XON字符之后发送继续。 | |
| fOutX | XON/XOFF 流量控制在发送时是否可用。如果为TRUE, 当 XOFF 值被收到的时候,发送停止;当 XON 值被收到的时候,发送继续 | |
| fInX | XON/XOFF 流量控制在接收时是否可用。如果为TRUE, 当 输入缓冲区已接收满XoffLim 字节时,发送XOFF字符;当输入缓冲区已经有XonLim 字节的空余容量时,发送XON字符 | |
| XonLim | 在XON字符发送前接收缓冲区内可允许的最小字节数 | |
| XoffLim | 在XOFF字符发送前接收缓冲区内可允许的最大字节数 | |
| XonChar | 指定XON字符 | |
| XoffChar | 指定XOFF字符 | |
| fDummy2 | 保留,未启用 | |
| wReserved | 未启用,必须设置为0 | |
| wReserved1 | 保留,未启用 |
C# SerialPort自定义串口DCB的更多相关文章
- C#用SerialPort实现串口通讯
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- Nodejs 使用 SerialPort 调用串口
工作经常使用串口读写数据,electron 想要替代原来的客户端,串口成了必须要突破的障碍. get --> https://github.com/EmergingTechnologyAdvi ...
- C#SerialPort实现串口控制继电器
最近做了一个小系统,麻雀虽小五脏俱全呀,用到各种线程控制,串口控制等技术.其中串口控制最麻烦,因为继电器的响应很快,根据不同的转接口,返回的数据质量是不一样的,所以不能直接wirte,然后马上read ...
- C#SerialPort如何读取串口数据并显示在TextBox上
SerialPort中串口数据的读取与写入有较大的不同.由于串口不知道数据何时到达,因此有两种方法可以实现串口数据的读取.一.线程实时读串口:二.事件触发方式实现. 由于线程实时读串口的效率不是十分高 ...
- c#实现串口操作 SerialPort
命名空间:using System.IO.Ports;该类提供了同步 I/O 和事件驱动的 I/O.对管脚和中断状态的访问以及对串行驱动程序属性的访问. 操作类声明: SerialPort sp = ...
- System.IO.Ports.SerialPort串口通信接收完整数据
C#中使用System.IO.Ports.SerialPort进行串口通信网上资料也很多,但都没有提及一些细节: 比如 串口有时候并不会一次性把你想要的数据全部传输给你,可能会分为1次,2次,3次分别 ...
- C#串口操作类,包括串口读写操作
串口进行操作的类,其中包括写和读操作,类可设置串口参数.设置接收函数.打开串口资源.关闭串口资源,操作完成后,一定要关闭串口.接收串口数据事件.接收数据出错事件.获取当前全部串口.把字节型转换成十六进 ...
- .Net Core跨平台应用研究-CustomSerialPort(增强型跨平台串口类库)
.Net Core跨平台应用研究-CustomSerialPort -增强型跨平台串口类库 摘要 在使用SerialPort进行串口协议解析过程中,经常遇到接收单帧协议数据串口接收事件多次触发,协议解 ...
- .Net Core 跨平台应用使用串口、串口通信 ,可能出现的问题、更简洁的实现方法
前些天在学习在 .NET Core下,跨平台使用串口通讯,有一篇文章说到在Linux/物联网下,实现通讯. 主要问题出现在以下两个类库 SerialPortStream flyfire.CustomS ...
随机推荐
- ES6 学习笔记之一 块作用域与let和const
---恢复内容开始--- 在学习ES6的块作用域和 let.const 之前,我们先来看看ES5以前的 var 关键字. var 关键字用于定义一个变量,通常我们会将其与变量的赋值合并为一条语句,就像 ...
- qt中的多线程
1.dialog.h #define DIALOG_H #include <QDialog>#include"mythread.h"namespace Ui {clas ...
- grep 同时满足多个关键字、满足任意关键字和排除关键字
1. 同时满足多个关键字 grep "word1" file_name | grep "word2" | grep "word3" 2. 满 ...
- PHP die与exit的区别
最近听见有人说die和exit区别,bula~bula.决心一探究竟. 翻了翻PHP 5.6的源码(源码的位置为zend目录下zend_language_scanner.l大约是1014~1020行) ...
- 洛谷P2891 Dining P1402 酒店之王【类二分图匹配】题解+代码
洛谷P2891 Dining P1402 酒店之王[类二分图匹配]题解+代码 酒店之王 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的 ...
- CENTOS6.6上搭建单实例ORACLE12C
本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: 自己在centos6.6上搭建的单实例oracle12c 由 ...
- 案例分析——BAT业务https化经历
一.前言 通常的http访问会遭到中间人攻击.网络嗅探等普通用户感知不到的恶意行为,这些行为会篡改用户浏览页面引导用户访问非法网站.抓取用户的上网行为以及个人信息.严重的会造成用户 ...
- C/C++语言简介之语言特点
一.基本特性 1.高级语言:它是把高级语言的基本结构和语句与低级语言的实用性结合起来的工作单元. 2.结构式语言:结构式语言的显著特点是代码及数据的分隔化,即程序的各个部分除了必要的信息交 ...
- web基础知识通信概述URI与http
1.url是什么,有什么作用: 说白了就是我们常说的网址:正规来说就是统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址. 互联网上的每个文件都有一个 ...
- C语言_指针变量的赋值与运算,很详细
指针变量的赋值 指针变量同普通变量一样,使用之前不仅要定义说明, 而且必须赋予具体的值.未经赋值的指针变量不能使用, 否则将造成系统混乱,甚至死机.指针变量的赋值只能赋予地址, 决不能赋予任何其它数据 ...