1. 西门子S7-1200与Modbus RTU通讯的基础架构
在工业自动化领域,Modbus RTU协议因其简单可靠的特点,成为PLC与变频器、仪表等设备通讯的通用语言。西门子S7-1200系列PLC通过CM 1241 RS485通讯模块(6ES7 241-1CH32-0XB0)实现物理层连接,其接线端子定义如下:
- 引脚3(RXD+/TXD+)对应A+线
- 引脚8(RXD-/TXD-)对应B-线
- 引脚5为信号地
硬件组态时需注意:
- 在TIA Portal中插入CM 1241模块后,需设置端口参数:
- 波特率:常见9600/19200/38400(需与从站一致)
- 校验位:偶校验(Even)是Modbus RTU的典型配置
- 停止位:1位或2位(根据从站要求)
- 终端电阻设置:
- 网络首尾设备需启用120Ω终端电阻
- 通过模块侧面的拨码开关SW1控制(ON=启用)
关键提示:实际布线时建议使用双绞屏蔽线,屏蔽层单端接地。我曾遇到因接地不良导致通讯断续的问题,后通过将屏蔽层接至PLC机柜接地铜排解决。
2. Modbus RTU协议栈的SCL实现解析
西门子提供了标准库"Modbus_RTU_Master",但实际项目中常需自定义功能。以下是用SCL编写的基础通讯函数:
scl复制FUNCTION "MB_RTU_SendCmd" : VOID
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
MB_ADDR : BYTE; // 从站地址
FC : BYTE; // 功能码
DATA_ADDR : WORD; // 寄存器地址
DATA_LEN : WORD; // 数据长度
END_VAR
VAR_TEMP
i : INT;
CRC : WORD := 16#FFFF;
END_VAR
BEGIN
// 构建报文头
#TX_BUF[0] := #MB_ADDR;
#TX_BUF[1] := #FC;
#TX_BUF[2] := #DATA_ADDR.HIGH_BYTE;
#TX_BUF[3] := #DATA_ADDR.LOW_BYTE;
// CRC计算(多项式0xA001)
FOR #i := 0 TO 3 DO
#CRC := #CRC XOR #TX_BUF[#i];
FOR 8 DO
IF #CRC.0 THEN
#CRC := SHR(IN := #CRC, N := 1) XOR 16#A001;
ELSE
#CRC := SHR(IN := #CRC, N := 1);
END_IF;
END_FOR;
END_FOR;
// 添加CRC校验
#TX_BUF[4] := #CRC.LOW_BYTE;
#TX_BUF[5] := #CRC.HIGH_BYTE;
// 触发发送
"MB_PORT".LEN := 6;
"MB_PORT".MODE := 1; // 发送模式
END_FUNCTION
典型功能码实现要点:
- 03功能码(读保持寄存器):需处理字节序转换(大端转小端)
- 06功能码(写单寄存器):注意地址对齐问题
- 16功能码(写多寄存器):需分段处理(最大长度限制)
3. 多设备轮询的时序设计与故障处理
3.1 时间片轮询算法实现
建立轮询表数据结构:
scl复制TYPE "MB_Polling_Item" :
STRUCT
Slave_ID : BYTE; // 从站地址
Func_Code : BYTE; // 功能码
Reg_Addr : WORD; // 寄存器地址
Data_Len : WORD; // 数据长度
Timeout : TIME := T#500ms;// 超时时间
Retry_Cnt : INT; // 重试计数
Data_PTR : POINTER; // 数据存储指针
END_STRUCT;
END_TYPE
轮询调度器核心逻辑:
- 使用OB30循环中断组织块(默认100ms周期)
- 状态机管理通讯阶段:
scl复制CASE #State OF 0: // 空闲状态 IF #Poll_Index < #Poll_Count THEN "MB_RTU_SendCmd"(...); #Timer := "MB_Poll_Table"[#Poll_Index].Timeout; #State := 1; // 进入等待响应 END_IF; 1: // 等待响应 IF "MB_PORT".DONE THEN IF 校验响应正确 THEN #State := 2; // 数据处理 ELSE #Retry_Cnt += 1; IF #Retry_Cnt > 3 THEN #Poll_Index += 1; // 跳过当前设备 #State := 0; ELSE #State := 0; // 立即重试 END_IF; END_IF; ELSIF #Timer <= T#0s THEN // 超时处理 #State := 0; #Poll_Index += 1; END_IF; END_CASE;
3.2 典型故障处理方案
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 偶发通讯中断 | 总线干扰 | 检查终端电阻,增加0.1uF滤波电容 |
| 持续超时 | 从站地址错误 | 用串口监听工具验证报文 |
| CRC校验失败 | 波特率不匹配 | 核对主从站波特率参数 |
| 数据错位 | 寄存器地址偏移 | 确认从站文档的地址基址 |
实测案例:某项目读取G120变频器电流值时,发现数据周期性异常。最终发现是:
- 变频器参数P2023(Modbus地址偏移)默认为1
- 程序中直接使用手册中的地址未做偏移
- 修改程序地址或设置P2023=0后解决
4. 性能优化与高级应用
4.1 加权动态轮询算法
对于关键设备(如变频器)需要更高刷新频率,可采用加权队列:
scl复制// 在轮询表中增加权重字段
TYPE "MB_Polling_Item" EXTENDS "MB_Polling_Item" :
STRUCT
Weight : INT := 1; // 默认权重
Counter : INT := 0; // 计数累加器
END_STRUCT;
END_TYPE
// 调度逻辑修改
FOR #i := 0 TO #Poll_Count-1 DO
#Poll_Table[#i].Counter += #Poll_Table[#i].Weight;
IF #Poll_Table[#i].Counter >= #Threshold THEN
#Next_Poll := #i;
#Poll_Table[#i].Counter := 0;
EXIT;
END_IF;
END_FOR;
4.2 与G120变频器的深度集成
通过Modbus实现G120控制的关键参数:
- 控制字1:Modbus地址0x047E(启动/停止控制)
- 状态字1:Modbus地址0x047F
- 主设定值:Modbus地址0x4000(百分比形式)
特殊处理要求:
- 控制字需要先发送"使能"信号(bit0=1)
- 速度设定值需转换为16384对应100%转速
- 状态字中的故障代码需解析(bit7=故障标志)
示例速度控制代码:
scl复制// 设置速度50%
"MB_RTU_WriteReg"(
MB_ADDR := 5,
FC := 16#06,
DATA_ADDR := 16#4000,
DATA_VAL := 8192); // 16384 * 0.5
// 发送启动命令
"MB_RTU_WriteReg"(
MB_ADDR := 5,
FC := 16#06,
DATA_ADDR := 16#047E,
DATA_VAL := 16#047F); // 使能+启动
5. 工程实践中的经验结晶
-
报文监听技巧:
- 使用USB转485适配器连接PC
- 打开Modbus Poll软件的监听模式
- 过滤特定从站地址分析交互过程
-
响应超时优化:
- 标准超时500ms可缩短至200ms(高速网络)
- 但需在从站参数设置响应延迟(如G120的P2022)
-
数据同步策略:
- 关键参数采用"写-读-校验"机制
- 对连续变量(如温度值)做平滑滤波处理
-
诊断增强:
- 在HMI上显示各从站最后通讯时间
- 对频繁超时的从站触发预警事件
某生产线实际应用数据:
- 32个从站轮询周期:原方案4.2秒 → 优化后1.8秒
- 通讯成功率:从92%提升至99.6%
- CPU负载:从35%降至18%
