2025-06-08 12:48:04 +08:00

207 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Modbus TCP 服务器模块
基于libmodbus库的Modbus TCP服务器实现提供完整的Modbus TCP服务器功能和回调机制。
## 功能特性
- 基于libmodbus的稳定实现
- 支持多客户端并发连接
- 完整的Modbus功能码支持
- 写操作回调机制,支持应用层错误码反馈
- 线程安全的数据访问和更新接口
- 跨平台支持Windows/Linux
## 支持的Modbus功能
### 读操作(自动处理)
- 读取线圈0x01
- 读取离散输入0x02
- 读取保持寄存器0x03
- 读取输入寄存器0x04
### 写操作(支持回调)
- 写单个线圈0x05
- 写单个保持寄存器0x06
- 写多个线圈0x0F
- 写多个保持寄存器0x10
## API接口
### 基本操作
```cpp
#include "ModbusTCPServer.h"
ModbusTCPServer server;
// 启动服务器
if (server.start(502, 10)) {
// 服务器启动成功
}
// 停止服务器
server.stop();
```
### 设置写操作回调
```cpp
// 设置写线圈回调
server.setWriteCoilsCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint8_t* values) -> ModbusTCPServer::ErrorCode {
// 处理写线圈请求
// unitId: 单元ID
// address: 起始地址
// quantity: 数量
// values: 写入的值
// 返回错误码
return ModbusTCPServer::ErrorCode::SUCCESS;
});
// 设置写寄存器回调
server.setWriteRegistersCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint16_t* values) -> ModbusTCPServer::ErrorCode {
// 处理写寄存器请求
// 检查地址范围、权限等
if (address >= 1000 && address < 2000) {
// 允许写入
return ModbusTCPServer::ErrorCode::SUCCESS;
} else {
// 拒绝写入 - 非法地址
return ModbusTCPServer::ErrorCode::ILLEGAL_DATA_ADDRESS;
}
});
```
### 数据更新接口
```cpp
// 更新单个数据
server.updateCoil(0, true);
server.updateHoldingRegister(100, 1234);
server.updateDiscreteInput(50, false);
server.updateInputRegister(200, 5678);
// 批量更新数据
std::vector<bool> coils = {true, false, true, false};
server.updateCoils(0, coils);
std::vector<uint16_t> registers = {1000, 2000, 3000};
server.updateHoldingRegisters(100, registers);
```
## 错误代码
服务器支持标准的Modbus异常代码
```cpp
enum class ErrorCode {
SUCCESS = 0, // 成功
ILLEGAL_FUNCTION = 1, // 非法功能码
ILLEGAL_DATA_ADDRESS = 2, // 非法数据地址
ILLEGAL_DATA_VALUE = 3, // 非法数据值
SERVER_FAILURE = 4, // 服务器故障
ACKNOWLEDGE = 5, // 确认
SERVER_BUSY = 6, // 服务器忙
NEGATIVE_ACKNOWLEDGE = 7, // 否定确认
MEMORY_PARITY = 8, // 内存奇偶校验错误
GATEWAY_PATH_UNAVAILABLE = 10, // 网关路径不可用
GATEWAY_TARGET_FAILED = 11 // 网关目标设备响应失败
};
```
## 完整使用示例
```cpp
#include "ModbusTCPServer.h"
#include <iostream>
#include <thread>
#include <chrono>
int main() {
ModbusTCPServer server;
// 设置写操作回调
server.setWriteCoilsCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint8_t* values) {
std::cout << "写线圈请求 - 单元ID: " << (int)unitId
<< ", 地址: " << address
<< ", 数量: " << quantity << std::endl;
return ModbusTCPServer::ErrorCode::SUCCESS;
});
server.setWriteRegistersCallback([](uint8_t unitId, uint16_t address, uint16_t quantity, const uint16_t* values) {
std::cout << "写寄存器请求 - 单元ID: " << (int)unitId
<< ", 地址: " << address
<< ", 数量: " << quantity << std::endl;
// 检查地址范围
if (address < 1000) {
return ModbusTCPServer::ErrorCode::ILLEGAL_DATA_ADDRESS;
}
return ModbusTCPServer::ErrorCode::SUCCESS;
});
// 启动服务器
if (!server.start(502, 10)) {
std::cerr << "启动服务器失败: " << server.getLastError() << std::endl;
return -1;
}
std::cout << "Modbus TCP服务器已启动端口: 502" << std::endl;
// 定期更新数据
for (int i = 0; i < 100; ++i) {
server.updateHoldingRegister(1000, i);
server.updateCoil(0, i % 2 == 0);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
// 停止服务器
server.stop();
std::cout << "服务器已停止" << std::endl;
return 0;
}
```
## 编译说明
### 依赖
- Qt 5.x 或更高版本
- C++17 编译器
- libmodbus源码已包含在VrNets模块中
### 构建
```bash
qmake ModbusTCPServer.pro
make
```
### 使用
该模块编译为静态库,在其他项目中包含:
```pro
LIBS += -L../Module/ModbusTCPServer -lModbusTCPServer
INCLUDEPATH += ../Module/ModbusTCPServer/Inc
```
## 特性说明
### 多客户端支持
- 支持同时处理多个客户端连接
- 使用select事件驱动模型单线程处理所有客户端
- 高效的资源利用,避免线程过多的问题
- 线程安全的数据访问
### 数据存储
- 内部使用libmodbus的mapping结构存储数据
- 支持10000个线圈、离散输入、保持寄存器和输入寄存器
- 所有数据操作都是线程安全的
### 回调机制
- 写操作会触发用户定义的回调函数
- 回调函数可以返回错误码来拒绝写操作
- 支持异步处理和验证
### 错误处理
- 完整的错误处理和状态反馈
- 支持标准Modbus异常代码
- 详细的错误信息获取接口