C# 串口通信中如何实现 DTR 握手功能?
C# 实现串口DTR握手的方案
.NET 自带的SerialPort类的Handshake枚举仅提供None、XOnXOff、RequestToSend、RequestToSendXOnXOff四个选项,没有原生的DTR握手选项,可通过以下两种方案实现:
方案1:手动控制DTR实现基础握手逻辑
适用于对实时性要求不高的场景,代码简单兼容性强,不需要调用平台API。
实现逻辑:
- 初始化串口时关闭默认流控,开启DTR引脚输出
- 通讯过程中根据对端DSR引脚状态或自定义流控规则,动态修改
DtrEnable属性实现流控
代码示例:
using System.IO.Ports; // 初始化串口配置 SerialPort serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One); serialPort.Handshake = Handshake.None; serialPort.DtrEnable = true; // 默认启用DTR引脚 serialPort.Open(); // 发送数据前判断流控状态,示例为标准DTR/DSR握手逻辑 if (!serialPort.DsrHolding) { // 对端未准备好,关闭DTR暂停发送 serialPort.DtrEnable = false; } else { // 对端准备就绪,开启DTR恢复发送 serialPort.DtrEnable = true; }
方案2:P/Invoke调用Win32 API实现原生DTR握手
适用于Windows平台下对实时性要求高,需要完全匹配Win32原生串口行为的场景,直接修改底层DCB结构体的fDtrControl字段实现硬件级握手。
代码示例:
using System; using System.IO.Ports; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; public static class SerialPortDtrExtension { // DTR控制模式常量 private const int DTR_CONTROL_HANDSHAKE = 0x02; private const int DCB_FLAGS_DTR_MASK = 0x0003; [StructLayout(LayoutKind.Sequential)] private struct DCB { public int DCBLength; public int BaudRate; public int Flags; public short wReserved; public short XonLim; public short XoffLim; public byte ByteSize; public byte Parity; public byte StopBits; public byte XonChar; public byte XoffChar; public byte ErrorChar; public byte EofChar; public byte EvtChar; public short wReserved1; } [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetCommState(SafeFileHandle hFile, ref DCB lpDCB); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetCommState(SafeFileHandle hFile, [In] ref DCB lpDCB); /// <summary> /// 为已打开的串口启用原生DTR硬件握手 /// </summary> /// <param name="port">已打开的SerialPort实例</param> public static void EnableDtrHardwareHandshake(this SerialPort port) { if (!port.IsOpen) throw new InvalidOperationException("串口需处于打开状态才可修改握手配置"); DCB dcb = new DCB(); dcb.DCBLength = Marshal.SizeOf(dcb); SafeFileHandle portHandle = port.BaseStream.SafeFileHandle; // 读取当前DCB配置 if (!GetCommState(portHandle, ref dcb)) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); // 修改DTR控制模式为硬件握手 dcb.Flags &= ~DCB_FLAGS_DTR_MASK; dcb.Flags |= DTR_CONTROL_HANDSHAKE; // 写入新DCB配置 if (!SetCommState(portHandle, ref dcb)) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } } // 调用示例 public void InitSerialPortWithDtrHandshake() { SerialPort serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One); serialPort.Handshake = Handshake.None; serialPort.Open(); // 启用原生DTR硬件握手 serialPort.EnableDtrHardwareHandshake(); // 后续正常使用串口即可,底层自动完成DTR流控逻辑 }
注意事项
- 方案2仅适用于Windows平台,依赖Win32系统API
- 修改DCB配置必须在串口打开后操作,否则会调用失败
内容的提问来源于stack exchange,提问作者domb
相关产品推荐
相关产品推荐

