跳到主要内容

串口通讯

Darra PLC 通过 SerialPortAdapter 支持 RS-232 和 RS-485 串口通讯, 适用于连接传感器、仪表、条码扫描器等串口设备。

支持接口

接口线缆距离拓扑典型场景
RS-2323~9 线≤15m点对点条码扫描器、打印机
RS-4852 线 (A/B)≤1200m多点总线仪表、变频器、传感器

连接配置

{
"protocol": "SerialPort",
"portName": "COM3",
"baudRate": 9600,
"dataBits": 8,
"parity": "None",
"stopBits": 1,
"handshake": "None",
"readTimeout": 1000,
"writeTimeout": 1000,
"encoding": "ASCII"
}

常用波特率: 2400, 4800, 9600, 19200, 38400, 57600, 115200

通讯模式

请求/响应模式

PLC 主动发送请求帧, 等待设备回复:

PLC  ──[请求帧]──→  设备
PLC ←──[响应帧]── 设备

被动接收模式

设备主动发送数据, PLC 被动接收 (如条码扫描器):

PLC  ←──[数据帧]──  设备 (触发扫描)

自定义协议帧

支持配置自定义帧格式:

字段说明示例
帧头起始标识0x02 (STX)
地址设备地址0x01
功能码操作类型0x03 (读取)
数据有效载荷可变长度
校验CRC/BCC/LRCCRC16-Modbus
帧尾结束标识0x03 (ETX)

代码示例

// 创建串口连接
var adapter = PLCDriverFactory.Create(ProtocolId.SerialPort);
await adapter.ConnectAsync(new ConnectionConfig
{
PortName = "COM3",
BaudRate = 9600,
DataBits = 8,
Parity = System.IO.Ports.Parity.None,
StopBits = System.IO.Ports.StopBits.One
});

// 发送请求并接收响应
byte[] request = new byte[] { 0x02, 0x01, 0x03, 0x00, 0x00, 0xXX, 0xXX, 0x03 };
await adapter.WriteAsync("raw", request);
var response = await adapter.ReadAsync("raw", 256);

// 断开连接
await adapter.DisconnectAsync();

PLC 变量映射

串口接收的数据可映射到 PLC 变量:

接收缓冲区[0..1]  →  MW6000   (INT, 传感器值 1)
接收缓冲区[2..3] → MW6002 (INT, 传感器值 2)
接收缓冲区[4..7] → MD6004 (REAL, 温度值)
RS-485 总线注意事项
  • 总线两端需加 120 ohm 终端电阻
  • 同一总线最多 32 个节点 (标准驱动器), 使用增强驱动器可达 256 个
  • 避免星形接线, 应使用菊花链拓扑
  • 发送完成后须切换为接收模式 (半双工)
调试技巧

使用 IDE 内置的串口监视器可以查看原始收发数据 (十六进制/ASCII 双模式), 便于协议调试。

常见串口协议

PLC 串口对接的设备多种多样, 典型协议:

协议设备特点
Modbus RTU变频器、温控仪标准工业协议
Modbus ASCII老旧仪表可打印字符, 效率低
自定义 ASCII称重仪 / 条码枪STX + 数据 + ETX
自定义二进制专用设备各厂商私有
DNP3电力 SCADA多字节
IEC 60870-5电力调度多字节
SECS-I半导体设备复杂

Darra 通过协议解析器 (Protocol Parser) 框架把不同协议抽象成统一的"帧读写"接口。

帧分割策略

串口是字节流, 需要确定"一帧到哪里结束":

策略适用
起止符自定义 ASCII, 如 STX/ETX 包裹
固定长度每帧 N 字节, 约定好
长度字段帧头里含有长度字节
帧间超时Modbus RTU: 3.5 字符时间
换行符文本协议 (AT 指令)
校验和触发累计到出现有效 CRC 才切帧

协议解析器按配置选择一种或多种组合。

协议解析器配置示例

ASCII 称重仪

帧格式: STX(0x02) + 重量(6 ASCII) + 单位(2 ASCII) + CR(0x0D)
示例: 02 30 30 31 32 35 30 4B 47 0D → "001250KG"
{
"protocol": "Custom",
"framing": {
"type": "StartStop",
"start": [0x02],
"end": [0x0D]
},
"parser": [
{ "name": "weight", "offset": 0, "length": 6, "type": "ASCII" },
{ "name": "unit", "offset": 6, "length": 2, "type": "ASCII" }
]
}

条码枪

帧格式: 条码 + CR+LF
{
"framing": {
"type": "LineTerminator",
"terminator": [0x0D, 0x0A]
},
"parser": [
{ "name": "barcode", "type": "ASCIIUntilTerminator" }
]
}

二进制仪表

帧格式: AA 55 + 长度(1B) + 数据 + CRC16 LSB/MSB
{
"framing": {
"type": "LengthPrefixed",
"header": [0xAA, 0x55],
"lengthOffset": 2,
"lengthSize": 1,
"lengthIncludesHeader": false
},
"parser": [
{ "name": "cmd", "offset": 3, "length": 1, "type": "UInt8" },
{ "name": "value", "offset": 4, "length": 4, "type": "Int32BE" }
],
"validator": {
"type": "CRC16",
"offset": 8,
"polynomial": "Modbus"
}
}

RS-485 半双工

RS-485 是半双工, 发送和接收不能同时。发送时需要:

  1. 切换到发送模式 (某些 USB-485 适配器自动切, 有些靠 RTS)
  2. 发完数据 + 一个字符的"发送完成"等待时间
  3. 切换回接收模式

Darra 适配器的 Rs485Mode 支持:

模式实现
Auto适配器硬件自动切换 (推荐)
RTS用 RTS 信号控制
DTR用 DTR 信号控制
Timed发完后固定等一段时间

虚拟串口

开发阶段可以用虚拟串口对组做仿真:

  • com0com (Windows, 开源)
  • socat (Linux)
  • 虚拟串口驱动 (Darra 自带的 DarraVCP)

一对虚拟串口 (COM100 ↔ COM101):

  • Darra PLC 连 COM100
  • 测试脚本连 COM101 发模拟数据

流控制

流控制用途
默认, 大多数场景
RTS/CTS硬件流控, 快速串口 (115200+) 防止缓冲溢出
XON/XOFF软件流控, 文本协议
DTR/DSR设备状态指示

工业场景大多无流控, 靠协议层超时/重传。

编码

串口传输的字节如何解读成字符串:

编码字节支持
ASCII1 B英文
UTF-8可变 1~4 B多语言, 推荐
GB2312 / GBK可变 1~2 B中文老系统 (注: 此处仅串口协议解码, 非 EtherCAT 设备字符串. EtherCAT 字符串走 UTF-8/ASCII/Latin-1 兜底)
Shift-JIS可变 1~2 B日文设备
Latin-11 B西欧

PLC 侧的 STRING 类型默认 UTF-8, 串口帧解析时需要配置对端编码一致, 否则中文乱码。

多串口

一台机器可能挂多个串口 (主机 COM1, USB 扩展 COM3COM10, PCI 卡 COM11COM20)。IDE 侧:

  • 每个串口独立一个 Adapter 实例, 互相隔离
  • 可以同一协议挂多个串口 (如 4 路 Modbus RTU 并行)
  • 诊断面板按 COM 号显示每个串口的流量

串口转网络

物理串口不够用或距离远, 可以用串口服务器 (Serial-to-Ethernet):

PLC 电脑 —— TCP —— 串口服务器 ——串口—— 设备

Darra 支持直接连串口服务器的透传端口:

await adapter.ConnectAsync(new ConnectionConfig {
Host = "192.168.1.200",
Port = 4001, // 串口服务器第一个串口的透传端口
Protocol = "ModbusRTU"
});

适配器把 TCP 流当串口用, 上层协议无需变化。

命令重试策略

串口通讯不稳定, 重试是常态:

{
"retry": {
"maxAttempts": 3,
"delayMs": 100,
"backoff": "linear"
}
}

重试仅针对"超时"和"校验和错", 不重试"业务错" (如命令不支持)。

排错

症状处理
打不开串口COM 号被占 / 无权限
收到乱码波特率、校验位、停止位不匹配
偶发丢字节波特率太高 / 流控未开
半双工回显RS-485 发送时采到自己的信号, 靠时序忽略
长帧解析错帧间超时设小了, 帧被拆散
收发乱序多线程并发访问同一串口, 加锁
USB 串口断开后 COM 号变设备管理器里改成固定 COM