本教程演示如何通过 Modbus TCP 协议实现 PLC 与上位机或其他设备的通信。
前置条件
- KVPAC IDE 已安装并配置
- RTE 运行环境(模拟器或 STM32 设备)
- Modbus 调试工具(如 ModScan、Modbus Poll)
步骤 1:启用 Modbus
在目标平台配置文件中启用 Modbus 并设置参数:
{
"communication": {
"modbus_enabled": true,
"modbus_port": 502,
"modbus_slave_id": 1
}
}
步骤 2:定义 Modbus 映射变量
在 ST 程序中使用 AT % 修饰符将变量映射到 Modbus 寄存器:
PROGRAM ModbusExample
VAR
// 映射到 Modbus 输入寄存器 (30001-3xxxx)
temperature AT %IW* : INT;
pressure AT %IW* : INT;
// 映射到 Modbus 保持寄存器 (40001-4xxxx)
setpoint AT %QW* : INT := 500;
speed AT %QW* : INT := 0;
// 映射到 Modbus 线圈 (00001-0xxxx)
start_btn AT %IX* : BOOL;
motor_run AT %QX* : BOOL;
// 内部变量
running : BOOL := FALSE;
counter : INT := 0;
END_VAR
| 地址范围 | Modbus 区域 | KVPAC 映射 |
|---|---|---|
| 0xxxx | 线圈 (Coils) | AT %IX* / AT %QX* |
| 1xxxx | 离散输入 | AT %IX* (只读) |
| 3xxxx | 输入寄存器 | AT %IW* (只读) |
| 4xxxx | 保持寄存器 | AT %QW* (读写) |
步骤 3:编写通信逻辑
PROGRAM ModbusControl
VAR
// Modbus 映射
cmd_register AT %QW* : INT; // 命令寄存器
status_register AT %QW* : INT; // 状态寄存器
data_in AT %IW* : INT; // 数据输入
// 状态变量
system_state : INT := 0;
cmd_buffer : INT := 0;
END_VAR
// 读取命令
cmd_buffer := cmd_register;
// 命令解析
CASE cmd_buffer OF
1: // 启动
system_state := 1;
status_register := 100;
cmd_register := 0; // 清除命令
2: // 停止
system_state := 0;
status_register := 200;
cmd_register := 0;
3: // 读取状态
status_register := system_state;
cmd_register := 0;
ELSE:
// 无命令
END_CASE
步骤 4:使用 Modbus 调试
- 编译并下载程序到 RTE
- 启动 Modbus 调试工具(如 ModScan)
- 配置连接参数:
- IP:RTE 设备 IP(模拟器使用 127.0.0.1)
- 端口:502
- 从站 ID:1
- 读取保持寄存器地址 0(对应
cmd_register) - 写入值 1 触发启动命令
- 观察状态寄存器值变为 100
步骤 5:编写 Modbus 通信状态机
对于复杂的通信场景,建议使用状态机管理:
FUNCTION_BLOCK ModbusComm
VAR_INPUT
enable : BOOL;
request_data : INT;
slave_id : INT := 1;
END_VAR
VAR_OUTPUT
response_data : INT;
comm_ok : BOOL;
error_code : INT;
END_VAR
VAR
state : INT := 0;
timeout : INT := 0;
retry_count : INT := 0;
MAX_RETRIES : INT := 3;
END_VAR
IF NOT enable THEN
state := 0;
comm_ok := FALSE;
RETURN;
END_IF
CASE state OF
0: // 空闲
IF request_data > 0 THEN
state := 10;
timeout := 0;
END_IF
10: // 发送请求
// 写入请求寄存器
%QW10 := request_data;
state := 20;
timeout := 0;
20: // 等待响应
timeout := timeout + 1;
IF %IW10 > 0 THEN
// 收到响应
response_data := %IW10;
comm_ok := TRUE;
state := 0;
ELSIF timeout >= 100 THEN
// 超时处理
retry_count := retry_count + 1;
IF retry_count >= MAX_RETRIES THEN
error_code := 1; // 通信失败
comm_ok := FALSE;
state := 0;
retry_count := 0;
ELSE
state := 10; // 重试
END_IF
END_IF
END_CASE
END_FUNCTION_BLOCK
完整示例:温控系统
PROGRAM TempControl
VAR
// Modbus IO 映射
current_temp AT %IW* : INT;
target_temp AT %QW* : INT := 250; // 25.0°C
heater_ctrl AT %QX* : BOOL;
heater_status AT %IX* : BOOL;
// 控制参数
HYSTERESIS : INT := 10; // ±1.0°C
alarm_temp : INT := 500; // 50.0°C 报警
// 状态
alarm : BOOL := FALSE;
runtime : INT := 0;
END_VAR
// 温度控制 (PID 简化版 - 滞回控制)
IF current_temp < (target_temp - HYSTERESIS) THEN
heater_ctrl := TRUE;
ELSIF current_temp > (target_temp + HYSTERESIS) THEN
heater_ctrl := FALSE;
END_IF
// 高温报警
IF current_temp >= alarm_temp THEN
alarm := TRUE;
heater_ctrl := FALSE; // 紧急关断
END_IF
// 运行计时
IF heater_ctrl THEN
runtime := runtime + 1;
END_IF
常见问题
Q: Modbus 通信超时? A: 检查网络连接、防火墙设置,确认 Modbus 端口未被占用。
Q: 读取寄存器返回 0? A: 确认寄存器地址正确,变量已映射到正确的地址范围,设备已连接并运行。
Q: 多台设备如何区分? A: 每个 Modbus 从站设备设置唯一的 slave_id(1-247),主站通过 slave_id 寻址。