PHP和Go语言Modbus库使用指南:phpmodbus与go-modbus实战

PHP Modbus 库(phpmodbus)

phpmodbus 是一个用 PHP 实现的 Modbus UDP/TCP 通信库,项目托管在 Google Code Archive:code.google.com/p/phpmodbus(已归档)。它实现了 Modbus UDP 协议的基本功能,支持 FC03(读保持寄存器)、FC16(写多寄存器)、FC23(读/写多寄存器)。

尽管 Modbus UDP 在工业现场远不如 Modbus TCP 常见,但 phpmodbus 在某些特殊的 Web 应用场景中有独特价值——比如在 PHP 编写的 SCADA 看板网站中直接读取 Modbus UDP 设备的数据、或者通过浏览器界面远程控制 Modbus 设备。

安装与基础使用

<?php
// 引入 phpmodbus 库
require_once 'PhpModBus.php';

// 创建 Modbus UDP 主站实例
$modbus = new ModbusUdpMaster('192.168.1.100', 502);

try {
    // FC03: 读取从站 1,起始地址 0,10 个保持寄存器
    $data = $modbus->readMultipleRegisters(1, 0, 10);
    
    // 输出结果
    echo "读取到的寄存器数据:n";
    for ($i = 0; $i < count($data); $i++) {
        echo sprintf("  地址 %d: %d (0x%04X)n", $i, $data[$i], $data[$i]);
    }
} catch (Exception $e) {
    echo "Modbus 通信错误: " . $e->getMessage();
}
?>

FC16 写多个保持寄存器

<?php
$modbus = new ModbusUdpMaster('192.168.1.100', 502);

// 要写入的数据
$values = [100, 200, 300, 400];

// FC16: 从站 1,起始地址 10,写入 4 个寄存器
$modbus->writeMultipleRegister(1, 10, $values);
echo "写入成功n";
?>

FC23 组合读写

<?php
$modbus = new ModbusUdpMaster('192.168.1.100', 502);

// FC23: 读地址 0-9,同时写地址 10-13
$valuesToWrite = [99, 88, 77, 66];
$readData = $modbus->readWriteRegisters(1, 0, 10, 10, $valuesToWrite);

echo "读取数据: ";
print_r($readData);
echo "写入数据: ";
print_r($valuesToWrite);
?>

Go Modbus 库(goburrow/modbus)

go-modbus(全称 github.com/goburrow/modbus)是一个用 Go 语言编写的 Modbus 协议客户端库,GitHub 地址:github.com/goburrow/modbus。它被描述为”fault-tolerant, fail-fast”的实现——在设计上注重错误处理和快速失败,适合在可靠性和稳定性要求较高的工业边缘网关场景中使用。

⚠️ 注意:根据 modbus.org 2024 年的最新描述,该库仍处于”incubating”阶段,”do not use in production yet (more testing needed)”。虽然 API 设计优秀,但在生产环境中使用前需要充分测试。

安装

go get github.com/goburrow/modbus

Modbus TCP 客户端示例

package main

import (
    "fmt"
    "time"
    "github.com/goburrow/modbus"
)

func main() {
    // 创建 TCP 客户端
    handler := modbus.NewTCPClientHandler("192.168.1.100:502")
    handler.Timeout = 5 * time.Second
    handler.SlaveId = 1
    
    // 建立连接
    err := handler.Connect()
    if err != nil {
        fmt.Printf("连接失败: %vn", err)
        return
    }
    defer handler.Close()
    
    client := modbus.NewClient(handler)
    
    // 读取 10 个保持寄存器(地址 0-9)
    results, err := client.ReadHoldingRegisters(0, 10)
    if err != nil {
        fmt.Printf("读取失败: %vn", err)
        return
    }
    
    fmt.Println("寄存器数据:")
    for i := 0; i < len(results)-1; i += 2 {
        value := uint16(results[i])<<8 | uint16(results[i+1])
        fmt.Printf("  地址 %d: %d (0x%04X)n", i/2, value, value)
    }
    
    // 写入单个寄存器
    err = client.WriteSingleRegister(0, 1234)
    if err != nil {
        fmt.Printf("写入失败: %vn", err)
    } else {
        fmt.Println("写入成功")
    }
}

Modbus RTU 串口客户端

package main

import (
    "fmt"
    "github.com/goburrow/modbus"
)

func main() {
    // 创建 RTU 客户端(RS-485)
    handler := modbus.NewRTUClientHandler("/dev/ttyUSB0")
    handler.BaudRate = 9600
    handler.DataBits = 8
    handler.Parity = "N"   // 无校验
    handler.StopBits = 1
    handler.SlaveId = 1
    handler.Timeout = 3 * time.Second
    
    err := handler.Connect()
    if err != nil {
        panic(err)
    }
    defer handler.Close()
    
    client := modbus.NewClient(handler)
    results, _ := client.ReadHoldingRegisters(0, 5)
    fmt.Printf("RTU 读取结果: % Xn", results)
}

Go 语言在工业物联网中的优势

Go 语言近年来在工业物联网边缘网关领域越来越受欢迎,原因有几个:

  • 原生并发:goroutine 让同时连接数百个 Modbus 从站变得简单高效
  • 单二进制部署:编译后是一个独立可执行文件,无需运行时依赖(如 JVM、Python 解释器),部署极其简单
  • 跨平台编译GOOS=linux GOARCH=arm64 go build 即可交叉编译到 ARM Linux(树莓派、工控机)
  • 内存安全:相比 C 语言,Go 提供的自动垃圾回收和内存安全检查更适合编写稳定的长时间运行服务

Python Modbus Test Kit(modbus-tk)

Modbus Test Kit(modbus-tk)是一个 Python 实现的 Modbus 协议库,项目在 Google Code Archive。它支持 Modbus RTU 和 Modbus TCP,可以同时编写客户端和服务器。对于 Python 用户来说,另一个更现代的选择是 pymodbus,两者 API 风格不同但功能覆盖类似。

#!/usr/bin/env python3
# modbus-tk 基本使用示例
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_tcp

# 创建 TCP 主站
master = modbus_tcp.TcpMaster(host="192.168.1.100", port=502)
master.set_timeout(5.0)

# 读取从站 1 的保持寄存器 0-9
try:
    values = master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 10)
    print(f"读取结果: {values}")
except modbus_tk.modbus.ModbusError as exc:
    print(f"Modbus 错误: {exc}")

各语言 Modbus 库选择建议

使用场景推荐库语言状态
Web 应用集成phpmodbusPHP停更(UDP only)
边缘网关服务goburrow/modbusGoIncubating
自动化测试脚本modbus-tk / pymodbusPython活跃
嵌入式 LinuxlibmodbusC稳定

总结

Modbus 虽然是一个诞生超过 40 年的老协议,但在各种现代编程语言中都有对应的实现。PHP 的 phpmodbus 适合 Web 集成场景(尽管只支持 UDP),Go 的 goburrow/modbus 展现了 Go 语言在工业物联网边缘计算的潜力,Python 的 pymodbus 和 modbus-tk 则是编写自动化测试脚本和研究原型的最佳选择。根据你的项目语言栈和稳定性需求选择合适的库即可。

把这篇资料用于真实项目?

进入工具中心进行报文解析、CRC 校验和设备调试,或提交需求获取选型与接入建议。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注