使用 libmodbus 实现 Modbus 通信
使用 libmodbus 实现 Modbus 通信
Modbus 是一种广泛应用于工业自动化领域的通信协议,支持串行通信(如 RS-232、RS-485)和以太网通信(如 TCP/IP)。libmodbus
是一个开源的 C 库,提供了对 Modbus 协议的完整支持,使开发者能够轻松实现 Modbus 主站(Master)和从站(Slave)功能。
本文将详细介绍 libmodbus
的核心功能、使用方法以及如何利用它实现 Modbus 通信。
1. 什么是 libmodbus?
libmodbus
是一个用 C 语言编写的开源库,支持以下功能:
- Modbus RTU:基于串行通信(如 RS-232、RS-485)。
- Modbus TCP:基于以太网通信(TCP/IP)。
- Modbus ASCII:基于 ASCII 编码的串行通信。
- 主站和从站功能:支持 Modbus 主站(Master)和从站(Slave)的实现。
libmodbus
具有以下优点:
- 跨平台:支持 Linux、Windows、macOS 等操作系统。
- 易用性:提供了简洁的 API,方便开发者快速上手。
- 高性能:基于事件驱动模型,支持高并发通信。
2. 安装 libmodbus
在开始使用 libmodbus
之前,需要先安装它。
在 Ubuntu 上安装
sudo apt-get install libmodbus-dev
在 macOS 上安装
brew install libmodbus
在 Windows 上安装
可以从 libmodbus 官方网站 下载预编译的二进制文件,或者使用 vcpkg:
vcpkg install libmodbus
3. 核心功能
1. 创建 Modbus 上下文
libmodbus
使用上下文(Context)来管理 Modbus 通信。根据通信方式的不同,可以选择创建 RTU 或 TCP 上下文。
创建 RTU 上下文
modbus_t *ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
if (!ctx) {
fprintf(stderr, "Failed to create RTU context\n");
return -1;
}
创建 TCP 上下文
modbus_t *ctx = modbus_new_tcp("127.0.0.1", 502);
if (!ctx) {
fprintf(stderr, "Failed to create TCP context\n");
return -1;
}
2. 设置从站地址
在 Modbus 通信中,主站需要指定从站地址。
int slave_id = 1;
if (modbus_set_slave(ctx, slave_id) == -1) {
fprintf(stderr, "Failed to set slave ID\n");
return -1;
}
3. 连接 Modbus 设备
在创建上下文后,需要连接到 Modbus 设备。
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
4. 读写寄存器
libmodbus
提供了以下函数用于读写寄存器:
modbus_read_bits
:读取线圈状态(0x01 功能码)。modbus_read_input_bits
:读取离散输入状态(0x02 功能码)。modbus_read_registers
:读取保持寄存器(0x03 功能码)。modbus_read_input_registers
:读取输入寄存器(0x04 功能码)。modbus_write_bit
:写入单个线圈(0x05 功能码)。modbus_write_register
:写入单个保持寄存器(0x06 功能码)。modbus_write_bits
:写入多个线圈(0x0F 功能码)。modbus_write_registers
:写入多个保持寄存器(0x10 功能码)。
示例:读取保持寄存器
uint16_t tab_reg[10];
int rc = modbus_read_registers(ctx, 0, 10, tab_reg);
if (rc == -1) {
fprintf(stderr, "Failed to read registers: %s\n", modbus_strerror(errno));
return -1;
}
for (int i = 0; i < rc; i++) {
printf("Register %d: %d\n", i, tab_reg[i]);
}
示例:写入保持寄存器
uint16_t value = 1234;
if (modbus_write_register(ctx, 0, value) == -1) {
fprintf(stderr, "Failed to write register: %s\n", modbus_strerror(errno));
return -1;
}
5. 关闭连接和释放资源
在通信结束后,需要关闭连接并释放资源。
modbus_close(ctx);
modbus_free(ctx);
4. 示例代码
以下是一个完整的 Modbus TCP 主站示例,读取从站的保持寄存器并打印结果。
#include <modbus/modbus.h>
#include <stdio.h>
int main() {
// 创建 TCP 上下文
modbus_t *ctx = modbus_new_tcp("127.0.0.1", 502);
if (!ctx) {
fprintf(stderr, "Failed to create TCP context\n");
return -1;
}
// 设置从站地址
if (modbus_set_slave(ctx, 1) == -1) {
fprintf(stderr, "Failed to set slave ID\n");
modbus_free(ctx);
return -1;
}
// 连接到 Modbus 设备
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
// 读取保持寄存器
uint16_t tab_reg[10];
int rc = modbus_read_registers(ctx, 0, 10, tab_reg);
if (rc == -1) {
fprintf(stderr, "Failed to read registers: %s\n", modbus_strerror(errno));
modbus_close(ctx);
modbus_free(ctx);
return -1;
}
// 打印寄存器值
for (int i = 0; i < rc; i++) {
printf("Register %d: %d\n", i, tab_reg[i]);
}
// 关闭连接并释放资源
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
5. 实际应用场景
1. 工业自动化
libmodbus
可以用于与 PLC、传感器、执行器等设备进行通信,实现数据采集和控制。
2. 能源管理
通过 Modbus 协议,可以读取电表、水表等设备的能耗数据,实现能源管理。
3. 智能家居
libmodbus
可以用于与智能家居设备(如智能灯光、温控器)进行通信,实现远程控制。
6. 总结
libmodbus
是一个功能强大且易于使用的 Modbus 通信库,支持 RTU 和 TCP 协议,适用于多种应用场景。通过它,开发者可以轻松实现 Modbus 主站和从站功能,并与工业设备进行高效通信。
希望本文能帮助你快速上手 libmodbus
,并将其应用到实际项目中。如果你有任何问题或建议,欢迎在评论区留言!
参考文档
- libmodbus 官方网站
- libmodbus GitHub 仓库
- libmodbus 官方文档
Happy coding! 🚀