西门子 S7 协议通讯
Darra PLC 支持与西门子 S7 系列 PLC 的通讯, 基于成熟的工业通讯协议库实现。
支持型号
| 系列 | 型号 | 连接方式 | 说明 |
|---|---|---|---|
| S7-200 | CPU 22x | PPI/以太网 | 通过 Smart 模块 |
| S7-200 Smart | CPU SR/ST | 以太网 | 直连 |
| S7-300 | CPU 31x/31xC | 以太网 | MPI/PROFINET |
| S7-400 | CPU 41x | 以太网 | 机架号+槽号 |
| S7-1200 | CPU 121x | 以太网 | 需关闭优化块访问 |
| S7-1500 | CPU 151x | 以太网 | 需关闭优化块访问 |
S7-1200 和 S7-1500 需要在 TIA Portal 中进行以下设置:
- DB 块属性中取消勾选"优化的块访问"
- 在 CPU 属性 → 防护与安全中, 允许来自远程对象的 PUT/GET 通讯
存储区访问
| 存储区 | 标识 | 地址示例 | 说明 |
|---|---|---|---|
| I 输入映像 | I | I0.0, IB0, IW0 | 输入过程映像 |
| Q 输出映像 | Q | Q0.0, QB0, QW0 | 输出过程映像 |
| M 标志区 | M | M0.0, MB0, MW0, MD0 | 内部标志 |
| DB 数据块 | DB | DB1.DBX0.0, DB1.DBW0 | 数据块 |
| T 定时器 | T | T0 | 定时器当前值 |
| C 计数器 | C | C0 | 计数器当前值 |
连接配置
{
"protocol": "S7",
"host": "192.168.1.10",
"port": 102,
"rack": 0,
"slot": 1,
"plcType": "S7-1500",
"timeout": 3000
}
槽号参考:
- S7-300: Rack=0, Slot=2
- S7-400: Rack=0, Slot=3 (或实际槽号)
- S7-1200/1500: Rack=0, Slot=0 或 1
PLC 变量映射
将西门子 PLC 的数据映射到 Darra PLC 变量:
西门子 S7 地址 Darra PLC 变量
DB1.DBW0 ←→ MW1000 (INT)
DB1.DBD4 ←→ MD1004 (REAL)
DB1.DBX8.0 ←→ MX1008.0 (BOOL)
I0.0 ←→ IX0.0 (BOOL, 只读)
Q0.0 ←→ QX0.0 (BOOL)
代码示例
// 创建 S7 连接
var adapter = PLCDriverFactory.Create(ProtocolId.SiemensS7);
await adapter.ConnectAsync(new ConnectionConfig
{
Host = "192.168.1.10",
Port = 102,
Rack = 0,
Slot = 1,
PlcType = S7PlcType.S71500
});
// 读取 DB1.DBW0 (INT16)
var data = await adapter.ReadAsync("DB1.DBW0", 2);
short value = BitConverter.ToInt16(data, 0);
// 写入 DB1.DBD4 (REAL)
await adapter.WriteAsync("DB1.DBD4", BitConverter.GetBytes(3.14f));
建议使用批量读写减少通讯次数。一次最多读取 200 个字节, 多个不连续地址会自动优化合并。
S7 协议背景
S7 是西门子自有的 PLC 通讯协议, 也称为 ISO-on-TCP / S7comm。它跑在 TCP 端口 102 上, 底层用 ISO 8073 / RFC 1006 包装:
应用层: S7 PDU
会话层: COTP (ISO 8073)
传输层: TPKT (RFC 1006)
网络层: TCP (Port 102)
Darra 的 S7 适配器参考 HslCommunication 和 Snap7 等公开实现, 不调用西门子官方库。
PUT/GET 权限设置
S7-1200/1500 默认禁止外部 PUT/GET:
- TIA Portal 中选中 CPU → 属性 → 防护与安全 → 连接机制
- 勾选 "允许来自远程伙伴的 PUT/GET 通信访问"
- 重新下载 CPU 配置
如果不开启, 适配器会在连接阶段收到 S7 Error 0x81 认证失败, 日志里会有提示。
优化块访问
S7-1200/1500 的 DB 块有两种访问模式:
| 模式 | 外部可读写 | 内存布局 |
|---|---|---|
| 优化的块访问 (默认) | 需要按符号名 (不推荐) | 连续优化 |
| 标准的块访问 | 按地址偏移 (Darra 用这个) | 固定偏移 |
取消优化 方法:
- 在 DB 块上右键 → 属性 → 属性 → 取消勾选"优化的块访问"
- 保存, 重新编译 CPU
- 下载到 PLC
取消后可以通过 DB1.DBW0 这样的绝对地址访问。不取消的话只能用 S7-TIA 原生接口 (不支持跨厂商)。
地址语法
Darra 支持的 S7 地址语法:
| 格式 | 说明 | 示例 |
|---|---|---|
I<b>.<b> | 输入位 | I0.0 |
IB<n> / IW<n> / ID<n> | 输入字节/字/双字 | IW4 |
Q<b>.<b> / QB/QW/QD | 输出 | Q2.1 |
M<b>.<b> / MB/MW/MD | 标志 | MD20 |
DB<n>.DBX<b>.<b> | DB 位 | DB1.DBX0.0 |
DB<n>.DBB<b> / DBW / DBD | DB 字节/字/双字 | DB1.DBW10 |
T<n> | 定时器 (S7-300/400) | T3 |
C<n> | 计数器 (S7-300/400) | C5 |
S7-1200/1500 的时间型变量推荐用 DB 里的 TIME 类型, 避免使用传统 T0。
数据类型与字节序
S7 采用大端序 (Big-Endian), 多字节类型高位在前:
| 类型 | 大小 | 注意 |
|---|---|---|
| BOOL | 1 bit | 位地址 .0~.7 |
| BYTE | 1 B | |
| WORD / INT | 2 B | 大端 |
| DWORD / DINT | 4 B | 大端 |
| REAL | 4 B | IEEE 754 大端 |
| LREAL | 8 B | 仅 S7-1500 |
| STRING | 可变 | 长度前缀 + 实际长度 + 字符 |
| DT (Date_And_Time) | 8 B | BCD 编码 |
| S5TIME | 2 B | S5 格式定时器 |
PLC 里默认 BitConverter 是小端, 读回后需 Reverse:
var data = await adapter.ReadAsync("DB1.DBD0", 4);
float value = BitConverter.ToSingle(data.Reverse().ToArray(), 0);
或者使用 SDK 提供的 ReadReal:
float value = await adapter.ReadRealAsync("DB1.DBD0");
连接管理
S7 协议一个连接持有一个 Session。S7-1200/1500 默认最大并发连接数:
| 型号 | OP 连接 | S7 连接 | 其他 |
|---|---|---|---|
| S7-1200 | 3 | 8 | HMI/工程师同时连 |
| S7-1500 | 8 | 16 | |
| S7-1500 高规格 | 16 | 64 |
超过上限后新连接被拒绝。Darra 的连接池设计上保持一个固定连接复用, 避免对端耗尽。
批量读写优化
S7 支持一次请求读 / 写多个不连续项 (最多 19 项, PDU 长度 240 字节):
var batch = adapter.CreateBatch();
batch.Add("DB1.DBW0", 2); // 读 INT
batch.Add("DB1.DBD4", 4); // 读 REAL
batch.Add("M10.0", 1); // 读 BOOL
var results = await batch.ReadAsync();
适配器自动把多项请求打包到一个 PDU, 往返 1 次搞定。
DB 结构导入
在 IDE 中可以从 TIA Portal 导出的 Excel 或 XML 文件导入 DB 结构:
项目树 → 通讯 → S7 连接 → 右键 → 导入 DB 定义
导入后自动在变量表里生成对应符号, 地址自动填 DB<n>.DBx<offset>, 便于后续代码引用。
定时读取与事件订阅
适配器支持两种读取模式:
- 周期轮询: 固定间隔读, 低延迟要求
- 变化订阅: 在 Darra 侧做比对, 变化时触发事件, 减少下游处理量
adapter.Subscribe("DB1.DBW0", TimeSpan.FromMilliseconds(100), (addr, oldVal, newVal) => {
Console.WriteLine($"{addr}: {oldVal} → {newVal}");
});
时间同步
S7-300/400 的 SFC1 / SFC20 可以同步系统时钟。Darra 侧可以周期下发主机时间:
await adapter.WriteClockAsync(DateTime.Now);
var plcTime = await adapter.ReadClockAsync();
适合边缘计算场景需要 PLC 时间与上位一致。
错误码映射
| S7 Error | 含义 | 处理 |
|---|---|---|
| 0x00 | 成功 | |
| 0x05 | 地址错误 | 检查 DB 号、偏移 |
| 0x0A | 请求项不存在 | 检查 DB 是否已下载 |
| 0x0B | 对象类型不匹配 | 检查是否 ARRAY of BYTE |
| 0x81 | 用户会话权限不足 | 开启 PUT/GET |
| 0xD2 | 数据类型不支持 | 改用合适的类型 |
| 0xD8 | 长度错误 | 缩小请求长度 |
排错
| 症状 | 处理 |
|---|---|
| 连接超时 | 检查 IP、Rack/Slot、端口 102 |
| 认证失败 | TIA 里开 PUT/GET |
| 读取返回 0 | DB 被"优化块访问"保护 |
| 偶发错误 0x0A | 刚下载完 CPU, 等几秒 |
| 低速 (100ms+) | PDU 小, 开启批量读 |
| 中文字符串乱码 | STRING 类型按 Windows-1252, 改用 WSTRING |