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

4.9 KiB
Raw Blame History

Modbus TCP 服务器模块

基于libmodbus库的Modbus TCP服务器实现提供完整的Modbus TCP服务器功能和回调机制。

功能特性

  • 基于libmodbus的稳定实现
  • 支持多客户端并发连接
  • 完整的Modbus功能码支持
  • 写操作回调机制,支持应用层错误码反馈
  • 线程安全的数据访问和更新接口
  • 跨平台支持Windows/Linux

支持的Modbus功能

读操作(自动处理)

  • 读取线圈0x01
  • 读取离散输入0x02
  • 读取保持寄存器0x03
  • 读取输入寄存器0x04

写操作(支持回调)

  • 写单个线圈0x05
  • 写单个保持寄存器0x06
  • 写多个线圈0x0F
  • 写多个保持寄存器0x10

API接口

基本操作

#include "ModbusTCPServer.h"

ModbusTCPServer server;

// 启动服务器
if (server.start(502, 10)) {
    // 服务器启动成功
}

// 停止服务器
server.stop();

设置写操作回调

// 设置写线圈回调
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;
    }
});

数据更新接口

// 更新单个数据
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异常代码

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          // 网关目标设备响应失败
};

完整使用示例

#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模块中

构建

qmake ModbusTCPServer.pro
make

使用

该模块编译为静态库,在其他项目中包含:

LIBS += -L../Module/ModbusTCPServer -lModbusTCPServer
INCLUDEPATH += ../Module/ModbusTCPServer/Inc

特性说明

多客户端支持

  • 支持同时处理多个客户端连接
  • 使用select事件驱动模型单线程处理所有客户端
  • 高效的资源利用,避免线程过多的问题
  • 线程安全的数据访问

数据存储

  • 内部使用libmodbus的mapping结构存储数据
  • 支持10000个线圈、离散输入、保持寄存器和输入寄存器
  • 所有数据操作都是线程安全的

回调机制

  • 写操作会触发用户定义的回调函数
  • 回调函数可以返回错误码来拒绝写操作
  • 支持异步处理和验证

错误处理

  • 完整的错误处理和状态反馈
  • 支持标准Modbus异常代码
  • 详细的错误信息获取接口