Modbus 使用详解

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

Modbus 是 1979 年由 Modicon(现 Schneider Electric)开发的串行通信协议,现为工业自动化领域的 de facto 标准,用于 PLC、传感器、HMI 等设备间数据交换。它采用客户端-服务器(原 master-slave)模型:客户端发起请求,服务器响应。协议开放、简单,但无内置安全机制,依赖物理/网络隔离。

Modbus 关键特性
  • 数据模型:四个表(每个最多 65536 项):
    • 线圈(Coils):读/写,1 位(开关量)。
    • 离散输入(Discrete Inputs):只读,1 位。
    • 保持寄存器(Holding Registers):读/写,16 位字(配置值)。
    • 输入寄存器(Input Registers):只读,16 位字(测量值)。
  • 功能码(Function Codes):公共码(1-127):
    • 0x01:读线圈。
    • 0x02:读离散输入。
    • 0x03:读多个保持寄存器。
    • 0x04:读输入寄存器。
    • 0x05:写单个线圈。
    • 0x06:写单个保持寄存器。
    • 0x0F:写多个线圈。
    • 0x10:写多个保持寄存器。
    • 其他:0x16(掩码写寄存器)、0x17(读/写多个寄存器)等。
    • 异常响应:功能码 + 0x80 + 异常码(1:非法功能、2:非法地址等)。
  • PDU vs ADU
    • PDU:功能码(1 字节)+ 数据(最大 252 字节)。
    • ADU:PDU + 附加(地址、校验)。大端序编码。
  • 变体
    • Modbus RTU:二进制,串行(RS-232/485),CRC-16 校验,静默间隔定帧。
    • Modbus ASCII:ASCII 码,串行,LRC 校验,: 开始,CR/LF 结束(较少用)。
    • Modbus TCP:TCP/IP(端口 502),MBAP 头(事务 ID + 协议 ID 0 + 长度 + 单元 ID),无校验。
    • Modbus Plus:Schneider 专有,高速令牌环,非标准 Modbus。
  • 帧示例
    • RTU 读寄存器:地址(1B) + 0x03 + 起始(2B) + 数量(2B) + CRC(2B)。
    • TCP:事务ID(2B) + 0(2B) + 长度(2B) + 单元ID(1B) + PDU。
  • 错误处理:超时、无响应、异常响应。
  • 使用场景:工业控制、SCADA、能源管理、楼宇自动化。
  • 规范:Modbus.org 提供免费下载(Application Protocol V1.1b3、Serial Line 等),无重大更新(2020 年术语改为 client-server)。
Python 使用详解(pymodbus 库)

pymodbus 是纯 Python Modbus 栈,支持同步/异步、TCP/RTU/ASCII/UDP。最新稳定版 ~3.6.x(开发版 4.0+)。

安装

pip install pymodbus  # TCP 等
pip install "pymodbus[serial]"  # 加 RTU

TCP 客户端示例(读/写寄存器):

from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient('127.0.0.1', port=502)  # 或 '192.168.1.100'
client.connect()

# 读保持寄存器 (FC 03)
rr = client.read_holding_registers(address=0, count=5, slave=1)
if not rr.isError():
    print("寄存器值:", rr.registers)  # [val1, val2, ...]

# 写单个寄存器 (FC 06)
wr = client.write_register(address=0, value=123, slave=1)
if not wr.isError():
    print("写入成功")

# 读线圈 (FC 01)
rc = client.read_coils(address=0, count=10, slave=1)
print("线圈:", rc.bits)

client.close()

RTU 客户端示例(串口):

from pymodbus.client import ModbusSerialClient

client = ModbusSerialClient(method='rtu', port='/dev/ttyUSB0', baudrate=9600, parity='N', bytesize=8, stopbits=1)
client.connect()

rr = client.read_holding_registers(0, 5, slave=1)
print(rr.registers)

client.close()

服务器示例(TCP,模拟设备):

from pymodbus.server import StartTcpServer
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSlaveContext, ModbusServerContext

store = ModbusSlaveContext(
    di=ModbusSequentialDataBlock(0, [15]*100),  # 离散输入
    co=ModbusSequentialDataBlock(0, [False]*100),  # 线圈
    hr=ModbusSequentialDataBlock(0, [0]*100),  # 保持寄存器
    ir=ModbusSequentialDataBlock(0, [10]*100))  # 输入寄存器
context = ModbusServerContext(slaves=store, single=True)

StartTcpServer(context=context, address=("localhost", 502))
C 使用详解(libmodbus 库)

libmodbus 是高效 C 库,支持 TCP/RTU/ASCII,无依赖。最新版 ~3.1.x(活跃维护)。

安装

git clone https://github.com/stephane/libmodbus.git
cd libmodbus
./autogen.sh  # 或用 tarball
./configure
make
sudo make install

TCP 客户端示例(读保持寄存器):

#include <stdio.h>
#include <modbus.h>

int main() {
    modbus_t *ctx;
    uint16_t regs[10];
    int rc;

    ctx = modbus_new_tcp("127.0.0.1", 502);  // IP 和端口
    if (ctx == NULL) {
        fprintf(stderr, "分配上下文失败\n");
        return -1;
    }

    modbus_set_slave(ctx, 1);  // 单元 ID/slave ID

    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "连接失败: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

    rc = modbus_read_registers(ctx, 0, 5, regs);  // 地址 0,读 5 个
    if (rc == -1) {
        fprintf(stderr, "读取失败: %s\n", modbus_strerror(errno));
    } else {
        printf("读到 %d 个寄存器:\n", rc);
        for (int i = 0; i < rc; i++) {
            printf("regs[%d] = %u\n", i, regs[i]);
        }
    }

    modbus_close(ctx);
    modbus_free(ctx);
    return 0;
}

编译:gcc client.c -o client pkg-config --cflags --libs libmodbus``

RTU 客户端示例

modbus_t *ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
modbus_set_slave(ctx, 1);
modbus_connect(ctx);
modbus_read_registers(ctx, 0, 5, regs);
// ... 同上
modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);  // 如需 RS485

服务器:用 modbus_mapping_new() 创建映射,modbus_tcp_listen() 监听,modbus_reply() 处理请求。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值