最近搞了个小项目,200SMART带2台V20变频器+7个球阀,Modbus RTU轮询搞了半天,踩了点坑,分享下实际怎么弄的——
200smart modbus rtu 轮询 实际项目案例和2台西门子v20变频器+7个阀的轮询,变频器写入频率,读取频率,启停控制,运行及故障信号反馈球阀开关控制,开关型号反馈。
·
200smart modbus rtu 轮询 实际项目案例 和2台西门子v20变频器+7个阀的轮询,变频器写入频率,读取频率,启停控制,运行及故障信号反馈 球阀开关控制,开关型号反馈
先明确硬件&协议配置
200SMART用PORT0做Modbus主站,波特率9600、偶校验、停止位1;
- V20站号1/2:控制字(启停)、频率(读写)、状态(运行/故障);
- 球阀站号3:线圈(控制开关)、离散输入(反馈);
关键先查手册! V20的Modbus地址是协议绝对地址,但200SMART的MBUS_MSG指令用的是偏移地址——比如协议里的40001(实际频率),指令里要写「1」(偏移从1开始),这个坑我踩过3次!
核心代码:状态机轮询逻辑
Modbus是串行通信,同一时间只能发1个请求,所以用状态机轮询(避免多请求冲突),直接上SCL(比梯形图清晰):
VAR
// Modbus主站实例
MBUS_Master: MBUS_MASTER;
// V201参数(站号1)
V201_Station: USINT := 1;
V201_SetFreq: REAL := 50.0; // 设定频率(Hz)
V201_ReadFreq: REAL; // 实际频率(Hz)
V201_CtrlWord: UINT := 1151; // 启动正转(V20控制字:0x047F)
V201_StatusWord: UINT; // 状态字(运行/故障)
V201_Running: BOOL; // 运行反馈
V201_Fault: BOOL; // 故障反馈
// V202参数(站号2)
V202_Station: USINT := 2;
V202_SetFreq: REAL := 40.0;
V202_ReadFreq: REAL;
V202_CtrlWord: UINT := 1150; // 停止(0x047E)
V202_StatusWord: UINT;
V202_Running: BOOL;
V202_Fault: BOOL;
// 球阀参数(站号3)
Valve_Station: USINT := 3;
Valve_Coil: ARRAY[0..6] OF BOOL; // 7个阀的控制输出
Valve_Feedback: ARRAY[0..6] OF BOOL; // 7个阀的反馈
Valve_Fault: ARRAY[0..6] OF BOOL; // 反馈校验故障
// 轮询状态机
Poll_State: USINT := 1;
END_VAR
// 主站初始化(上电一次就行)
IF NOT MBUS_Master.Initialized THEN
MBUS_Master.Port := 0;
MBUS_Master.BaudRate := 9600;
MBUS_Master.Parity := 1; // 偶校验
MBUS_Master.StopBits := 1;
MBUS_Master.Timeout := 1000; // 超时1s
MBUS_Master.Initialized := TRUE;
END_IF;
// 状态机轮询
CASE Poll_State OF
// 1. 读V201实际频率(功能码03,偏移地址1→协议40001)
1:
IF NOT MBUS_Master.Active THEN // 上一个请求完成
MBUS_Master.Station := V201_Station;
MBUS_Master.Function := 3;
MBUS_Master.Address := 1; // 协议40001=偏移1
MBUS_Master.Length := 1;
MBUS_Master.DataPtr := ADR(V201_ReadFreq);
MBUS_Master.Enable := TRUE;
Poll_State := 2;
END_IF;
// 2. 写V201设定频率(功能码06,偏移地址1)
2:
IF MBUS_Master.Done THEN // 读成功
// 注意:V20频率分辨率0.01Hz,要转成整数(50Hz→5000)
VAR_TEMP Write_Freq_INT: INT := INT(V201_SetFreq * 100);
MBUS_Master.Station := V201_Station;
MBUS_Master.Function := 6;
MBUS_Master.Address := 1;
MBUS_Master.DataPtr := ADR(Write_Freq_INT);
MBUS_Master.Enable := TRUE;
Poll_State := 3;
ELSIF MBUS_Master.Error THEN // 读失败,重试
Poll_State := 1;
END_IF;
// 3. 读V201状态字(功能码03,偏移地址0→协议40000)
3:
IF MBUS_Master.Done THEN
MBUS_Master.Station := V201_Station;
MBUS_Master.Function := 3;
MBUS_Master.Address := 0; // 协议40000=偏移0
MBUS_Master.Length := 1;
MBUS_Master.DataPtr := ADR(V201_StatusWord);
MBUS_Master.Enable := TRUE;
Poll_State := 4;
END_IF;
// 4. 处理V202(和V201逻辑一致,省略重复代码)
4:
IF MBUS_Master.Done THEN
// 读V202频率→写设定→读状态...
Poll_State := 5;
END_IF;
// 5. 写7个球阀控制(功能码15,偏移地址0→协议00001)
5:
IF MBUS_Master.Done THEN
MBUS_Master.Station := Valve_Station;
MBUS_Master.Function := 15; // 写多个线圈
MBUS_Master.Address := 0;
MBUS_Master.Length := 7;
MBUS_Master.DataPtr := ADR(Valve_Coil);
MBUS_Master.Enable := TRUE;
Poll_State := 6;
END_IF;
// 6. 读7个球阀反馈(功能码02,偏移地址0→协议10001)
6:
IF MBUS_Master.Done THEN
MBUS_Master.Station := Valve_Station;
MBUS_Master.Function := 2; // 读多个离散输入
MBUS_Master.Address := 0;
MBUS_Master.Length := 7;
MBUS_Master.DataPtr := ADR(Valve_Feedback);
MBUS_Master.Enable := TRUE;
Poll_State := 1; // 循环轮询
ELSIF MBUS_Master.Error THEN
Poll_State := 5; // 写失败重试
END_IF;
END_CASE;
// 状态字解析(V20状态字:位0=运行,位2=故障)
V201_Running := (V201_StatusWord AND 1) = 1;
V201_Fault := (V201_StatusWord AND 4) = 4;
// 球阀反馈校验(控制≠反馈→故障)
FOR i := 0 TO 6 DO
Valve_Fault[i] := (Valve_Coil[i] <> Valve_Feedback[i]);
END_FOR;
代码里的「坑」分析(实际踩过的)
- 地址偏移搞反:
一开始把协议40001直接写进Address,结果读不到数据——200SMART的MBUS_MSG是偏移地址(协议40001=偏移1,40000=偏移0),手册里藏在「Modbus协议映射」小节,没仔细看真的坑!
- 频率没转整数:
V20的频率寄存器是16位整数(0.01Hz分辨率),直接写REAL(比如50.0)会乱码——必须乘100转INT(5000),读回来再除100转REAL,现场调试时变频器半天没反应,以为硬件坏了...
- 没做反馈校验:
球阀控制输出ON,但反馈OFF,当时没报警,导致现场漏液——后来加了Valve_Fault比较,客户才说「终于知道之前为啥偶尔出问题了」...
实际项目效果
- 轮询周期≈200ms(2台V20+7个阀,速度够);
- 变频器启停响应<500ms,频率调节无波动;
- 球阀开关反馈实时校验,故障立即报警;
最后碎碎念:做工业通信别想当然,手册里的「小细节」(比如地址偏移、数据类型)才是坑王!踩过一次,下次看到Modbus地址就会先确认「是偏移还是绝对」——这就是经验吧~
200smart modbus rtu 轮询 实际项目案例 和2台西门子v20变频器+7个阀的轮询,变频器写入频率,读取频率,启停控制,运行及故障信号反馈 球阀开关控制,开关型号反馈

更多推荐
所有评论(0)