嵌入式开发之modbus库封装开发

Modbus 协议简介

Modbus 是一种串行通信协议,广泛应用于工业自动化领域。它定义了控制器之间如何通过串行链路通信,支持 RTU、ASCII 和 TCP 三种传输模式。下面为你分享一个基于 C 语言的 Modbus 库封装实现,支持 RTU 和 TCP 两种模式。

库设计思路

这个 Modbus 库采用分层设计思想,将协议处理与硬件接口分离,主要包含以下模块:

  • 协议核心层:处理 Modbus 协议逻辑
  • 传输层:实现 RTU 和 TCP 传输
  • 硬件抽象层:提供串口和网络接口
  • API 层:提供简洁的用户接口

完整代码实现

下面是完整的 Modbus 库实现代码:

/* modbus.h - Modbus协议库头文件 */
#ifndef __MODBUS_H__
#define __MODBUS_H__

#include <stdint.h>
#include <stdbool.h>

/* 错误码定义 */
typedef enum {
    MODBUS_OK = 0,
    MODBUS_ERROR_PARAM,
    MODBUS_ERROR_INIT,
    MODBUS_ERROR_CONNECT,
    MODBUS_ERROR_DISCONNECT,
    MODBUS_ERROR_TRANSMIT,
    MODBUS_ERROR_RECEIVE,
    MODBUS_ERROR_TIMEOUT,
    MODBUS_ERROR_PROTOCOL,
    MODBUS_ERROR_SLAVE,
    MODBUS_ERROR_MEMORY
} ModbusError;

/* Modbus功能码 */
typedef enum {
    MB_FC_READ_COILS = 0x01,              /* 读线圈 */
    MB_FC_READ_DISCRETE_INPUTS = 0x02,    /* 读离散输入 */
    MB_FC_READ_HOLDING_REGISTERS = 0x03,  /* 读保持寄存器 */
    MB_FC_READ_INPUT_REGISTERS = 0x04,    /* 读输入寄存器 */
    MB_FC_WRITE_SINGLE_COIL = 0x05,       /* 写单个线圈 */
    MB_FC_WRITE_SINGLE_REGISTER = 0x06,   /* 写单个寄存器 */
    MB_FC_WRITE_MULTIPLE_COILS = 0x0F,    /* 写多个线圈 */
    MB_FC_WRITE_MULTIPLE_REGISTERS = 0x10 /* 写多个寄存器 */
} ModbusFunctionCode;

/* Modbus异常码 */
typedef enum {
    MB_EX_ILLEGAL_FUNCTION = 0x01,         /* 不支持的功能码 */
    MB_EX_ILLEGAL_DATA_ADDRESS = 0x02,     /* 不支持的数据地址 */
    MB_EX_ILLEGAL_DATA_VALUE = 0x03,       /* 不支持的数据值 */
    MB_EX_SERVER_DEVICE_FAILURE = 0x04,    /* 服务器设备故障 */
    MB_EX_ACKNOWLEDGE = 0x05,              /* 确认请求,需要长时间处理 */
    MB_EX_SERVER_DEVICE_BUSY = 0x06,       /* 服务器设备忙 */
    MB_EX_MEMORY_PARITY_ERROR = 0x08,      /* 内存奇偶校验错误 */
    MB_EX_GATEWAY_PATH_UNAVAILABLE = 0x0A, /* 网关路径不可用 */
    MB_EX_GATEWAY_TARGET_DEVICE_FAILED = 0x0B /* 目标设备响应失败 */
} ModbusExceptionCode;

/* Modbus传输模式 */
typedef enum {
    MB_RTU,
    MB_TCP
} ModbusMode;

/* 硬件接口函数指针类型 */
typedef int (*ModbusSendFunc)(const uint8_t* data, uint32_t length, void* context);
typedef int (*ModbusReceiveFunc)(uint8_t* data, uint32_t max_length, uint32_t timeout_ms, void* context);

/* Modbus上下文结构 */
typedef struct {
    ModbusMode mode;                  /* 传输模式 */
    uint8_t slave_address;            /* 从站地址 */
    uint16_t transaction_id;          /* 事务ID(TCP模式) */
    
    ModbusSendFunc send_func;         /* 发送函数指针 */
    ModbusReceiveFunc receive_func;   /* 接收函数指针 */
    void* hw_context;                 /* 硬件上下文 */
    
    uint8_t* rx_buffer;               /* 接收缓冲区 */
    uint32_t rx_buffer_size;          /* 接收缓冲区大小 */
    
    uint32_t timeout_ms;              /* 超时时间(毫秒) */
    bool is_connected;                /* 连接状态 */
} ModbusContext;

/* API函数声明 */
ModbusError Modbus_Init(ModbusContext* ctx, ModbusMode mode, uint8_t slave_address,
                       ModbusSendFunc send_func, ModbusReceiveFunc receive_func,
                       void* hw_context, uint8_t* rx_buffer, uint32_t rx_buffer_size);
                       
ModbusError Modbus_SetTimeout(ModbusContext* ctx, uint32_t timeout_ms);
ModbusError Modbus_Connect(ModbusContext* ctx);
ModbusError Modbus_Disconnect(ModbusContext* ctx);
bool Modbus_IsConnected(ModbusContext* ctx);

/* 客户端功能函数 */
ModbusError Modbus_ReadCoils(ModbusContext* ctx, uint8_t slave_addr, 
                            uint16_t start_addr, uint16_t quantity, uint8_t* dest);
                            
ModbusError Modbus_ReadDiscreteInputs(ModbusContext* ctx, uint8_t slave_addr, 
                                     uint16_t start_addr, uint16_t quantity, uint8_t* dest);
                                     
ModbusError Modbus_ReadHoldingRegisters(ModbusContext* ctx, uint8_t slave_addr, 
                                       uint16_t start_addr, uint16_t quantity, uint16_t* dest);
                                       
ModbusError Modbus_ReadInputRegisters(ModbusContext* ctx, uint8_t slave_addr, 
                                      uint16_t start_addr, uint16_t quantity, uint16_t* dest);
                                      
ModbusError Modbus_WriteSingleCoil(ModbusContext* ctx, uint8_t slave_addr, 
                                  uint16_t addr, bool value);
                                  
ModbusError Modbus_WriteSingleRegister(ModbusContext* ctx, uint8_t slave_addr, 
                                      uint16_t addr, uint16_t value);
                                      
ModbusError Modbus_WriteMultipleCoils(ModbusContext* ctx, uint8_t slave_addr, 
                                     uint16_t start_addr, uint16_t quantity, const uint8_t* src);
                                     
ModbusError Modbus_WriteMultipleRegisters(ModbusContext* ctx, uint8_t slave_addr, 
                                         uint16_t start_addr, uint16_t quantity, const uint16_t* src);

/* 服务器端功能函数 */
ModbusError Modbus_ProcessRequest(ModbusContext* ctx, 
                                 uint8_t* response, uint32_t* response_length);

/* 辅助函数 */
const char* Modbus_GetErrorString(ModbusError error);
const char* Modbus_GetExceptionString(ModbusExceptionCode exception);

#endif /* __MODBUS_H__ */

/* modbus.c - Modbus协议库实现文件 */
#include "modbus.h"
#include <string.h>
#include <stdlib.h>

/* RTU帧最小长度: 从站地址(1) + 功能码(1) + 数据(至少1) + CRC(2) */
#define MB_RTU_MIN_FRAME_LENGTH 5

/* TCP帧最小长度: MBAP(6) + 从站地址(1) + 功能码(1) + 数据(至少1) */
#define MB_TCP_MIN_FRAME_LENGTH 9

/* 最大PDU长度 */
#define MB_MAX_PDU_LENGTH 253

/* 错误信息表 */
static const char* error_messages[] = {
    "Success",
    "Parameter error",
    "Initialization error",
    "Connection error",
    "Disconnection error",
    "Transmission error",
    "Reception error",
    "Timeout error",
    "Protocol error",
    "Slave error",
    "Memory error"
};

/* 异常信息表 */
static const char* exception_messages[] = {
    "Unknown exception",
    "Illegal function",
    "Illegal data address",
    "Illegal data value",
    "Server device failure",
    "Acknowledge",
    "Server device busy",
    "Memory parity error",
    "Unknown exception 0x08",
    "Unknown exception 0x09",
    "Gateway path unavailable",
    "Gateway target device failed to respond"
};

/* 计算CRC16校验值 */
static uint16_t modbus_crc16(const uint8_t* data, uint32_t length) {
    uint16_t crc = 0xFFFF;
    uint32_t i, j;
    
    for (i = 0; i < length; i++) {
        crc ^= (uint16_t)data[i];
        
        for (j = 0; j < 8; j++) {
            if ((crc & 0x0001) != 0) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    
    return crc;
}

/* 初始化Modbus上下文 */
ModbusError Modbus_Init(ModbusContext* ctx, ModbusMode mode, uint8_t slave_address,
                       ModbusSendFunc send_func, ModbusReceiveFunc receive_func,
                       void* hw_context, uint8_t* rx_buffer, uint32_t rx_buffer_size) {
    if (!ctx || !send_func || !receive_func || !rx_buffer || rx_buffer_size < MB_RTU_MIN_FRAME_LENGTH) {
        return MODBUS_ERROR_PARAM;
    }
    
    memset(ctx, 0, sizeof(ModbusContext));
    
    ctx->mode = mode;
    ctx->slave_address = slave_address;
    ctx->send_func = send_func;
    ctx->receive_func = receive_func;
    ctx->hw_context = hw_context;
    ctx->rx_buffer = rx_buffer;
    ctx->rx_buffer_size = rx_buffer_size;
    ctx->timeout_ms = 1000;  /* 默认超时1秒 */
    ctx->is_connected = false;
    
    return MODBUS_OK;
}

/* 设置超时时间 */
ModbusError Modbus_SetTimeout(ModbusContext* ctx, uint32_t timeout_ms) {
    if (!ctx) {
        return MODBUS_ERROR_PARAM;
    }
    
    ctx->timeout_ms = timeout_ms;
    return MODBUS_OK;
}

/* 连接Modbus设备 */
ModbusError Modbus_Connect(ModbusContext* ctx) {
    if (!ctx) {
        return MODBUS_ERROR_PARAM;
    }
    
    ctx->is_connected = true;
    ctx->transaction_id = 0;
    
    return MODBUS_OK;
}

/* 断开Modbus连接 */
ModbusError Modbus_Disconnect(ModbusContext* ctx) {
    if (!ctx) {
        return MODBUS_ERROR_PARAM;
    }
    
    ctx->is_connected = false;
    return MODBUS_OK;
}

/* 检查连接状态 */
bool Modbus_IsConnected(ModbusContext* ctx) {
    return (ctx != NULL) ? ctx->is_connected : false;
}

/* 发送Modbus请求并接收响应 */
static ModbusError modbus_exchange(ModbusContext* ctx, uint8_t* request, uint32_t request_length,
                                  uint32_t* response_length) {
    int result;
    
    if (!ctx || !request || !response_length) {
        return MODBUS_ERROR_PARAM;
    }
    
    if (!ctx->is_connected) {
        return MODBUS_ERROR_CONNECT;
    }
    
    /* 发送请求 */
    result = ctx->send_func(request, request_length, ctx->hw_context);
    if (result != (int)request_length) {
        return MODBUS_ERROR_TRANSMIT;
    }
    
    /* 接收响应 */
    result = ctx->receive_func(ctx->rx_buffer, ctx->rx_buffer_size, ctx->timeout_ms, ctx->hw_context);
    if (result <= 0) {
        return (result == 0) ? MODBUS_ERROR_TIMEOUT : MODBUS_ERROR_RECEIVE;
    }
    
    *response_length = (uint32_t)result;
    return MODBUS_OK;
}

/* 构建并发送Modbus请求 */
static ModbusError modbus_send_request(ModbusContext* ctx, uint8_t slave_addr, 
                                      ModbusFunctionCode func_code, uint16_t start_addr, 
                                      uint16_t quantity, const uint8_t* data, uint16_t data_length,
                                      uint32_t* response_length) {
    uint8_t request[256];
    uint32_t request_length = 0;
    uint16_t crc;
    
    if (!ctx || !response_length) {
        return MODBUS_ERROR_PARAM;
    }
    
    if (ctx->mode == MB_TCP) {
        /* TCP模式: MBAP头(6字节) + PDU */
        /* 事务标识符 */
        request[request_length++] = (ctx->transaction_id >> 8) & 0xFF;
        request[request_length++] = ctx->transaction_id & 0xFF;
        ctx->transaction_id++;
        
        /* 协议标识符(0表示Modbus) */
        request[request_length++] = 0;
        request[request_length++] = 0;
        
        /* 长度字段(剩余PDU长度) */
        uint16_t pdu_length = 1 + 1 + 2 + ((data) ? data_length : 0);
        request[request_length++] = (pdu_length >> 8) & 0xFF;
        request[request_length++] = pdu_length & 0xFF;
        
        /* 单元标识符(从站地址) */
        request[request_length++] = slave_addr;
    } else {
        /* RTU模式: 从站地址 + PDU + CRC */
        request[request_length++] = slave_addr;
    }
    
    /* 功能码 */
    request[request_length++] = func_code;
    
    /* 起始地址 */
    request[request_length++] = (start_addr >> 8) & 0xFF;
    request[request_length++] = start_addr & 0xFF;
    
    /* 数量 */
    if (quantity > 0) {
        request[request_length++] = (quantity >> 8) & 0xFF;
        request[request_length++] = quantity & 0xFF;
    }
    
    /* 附加数据 */
    if (data && data_length > 0) {
        memcpy(&request[request_length], data, data_length);
        request_length += data_length;
    }
    
    if (ctx->mode == MB_RTU) {
        /* 计算并添加CRC校验 */
        crc = modbus_crc16(request, request_length);
        request[request_length++] = crc & 0xFF;
        request[request_length++] = (crc >> 8) & 0xFF;
    }
    
    /* 发送请求并接收响应 */
    return modbus_exchange(ctx, request, request_length, response_length);
}

/* 解析Modbus响应 */
static ModbusError modbus_parse_response(ModbusContext* ctx, uint32_t response_length,
                                        uint8_t* func_code, uint8_t** data, uint32_t* data_length) {
    uint8_t* response = ctx->rx_buffer;
    uint16_t crc, received_crc;
    
    if (!ctx || !response_length || !func_code || !data || !data_length) {
        return MODBUS_ERROR_PARAM;
    }
    
    if (response_length < ((ctx->mode == MB_TCP) ? MB_TCP_MIN_FRAME_LENGTH : MB_RTU_MIN_FRAME_LENGTH)) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    if (ctx->mode == MB_TCP) {
        /* 检查事务标识符 */
        uint16_t transaction_id = (response[0] << 8) | response[1];
        if (transaction_id != (ctx->transaction_id - 1)) {
            return MODBUS_ERROR_PROTOCOL;
        }
        
        /* 检查协议标识符 */
        uint16_t protocol_id = (response[2] << 8) | response[3];
        if (protocol_id != 0) {
            return MODBUS_ERROR_PROTOCOL;
        }
        
        /* 检查长度字段 */
        uint16_t length = (response[4] << 8) | response[5];
        if (length != (response_length - 6)) {
            return MODBUS_ERROR_PROTOCOL;
        }
        
        /* 从站地址 */
        uint8_t slave_addr = response[6];
        
        /* 功能码 */
        *func_code = response[7];
        
        /* 数据部分 */
        *data = &response[8];
        *data_length = response_length - 8;
    } else {
        /* RTU模式: 验证CRC */
        crc = modbus_crc16(response, response_length - 2);
        received_crc = (response[response_length - 2]) | (response[response_length - 1] << 8);
        
        if (crc != received_crc) {
            return MODBUS_ERROR_PROTOCOL;
        }
        
        /* 从站地址 */
        uint8_t slave_addr = response[0];
        
        /* 功能码 */
        *func_code = response[1];
        
        /* 数据部分 */
        *data = &response[2];
        *data_length = response_length - 4;  /* 减去从站地址、功能码和CRC */
    }
    
    /* 检查是否为异常响应 */
    if (*func_code & 0x80) {
        if (*data_length < 1) {
            return MODBUS_ERROR_PROTOCOL;
        }
        
        ModbusExceptionCode exception = (ModbusExceptionCode)(*data[0]);
        (void)exception;  /* 避免未使用警告 */
        return MODBUS_ERROR_SLAVE;
    }
    
    return MODBUS_OK;
}

/* 读线圈(0x01) */
ModbusError Modbus_ReadCoils(ModbusContext* ctx, uint8_t slave_addr, 
                            uint16_t start_addr, uint16_t quantity, uint8_t* dest) {
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* data;
    uint32_t data_length;
    ModbusError error;
    
    if (!ctx || !dest || quantity == 0 || quantity > 2000) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_READ_COILS, start_addr, quantity, NULL, 0, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_READ_COILS || data_length < 1) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    uint8_t byte_count = data[0];
    if (data_length != (byte_count + 1) || ((byte_count * 8) < quantity)) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 复制数据 */
    memcpy(dest, &data[1], byte_count);
    
    return MODBUS_OK;
}

/* 读离散输入(0x02) */
ModbusError Modbus_ReadDiscreteInputs(ModbusContext* ctx, uint8_t slave_addr, 
                                     uint16_t start_addr, uint16_t quantity, uint8_t* dest) {
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* data;
    uint32_t data_length;
    ModbusError error;
    
    if (!ctx || !dest || quantity == 0 || quantity > 2000) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_READ_DISCRETE_INPUTS, start_addr, quantity, NULL, 0, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_READ_DISCRETE_INPUTS || data_length < 1) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    uint8_t byte_count = data[0];
    if (data_length != (byte_count + 1) || ((byte_count * 8) < quantity)) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 复制数据 */
    memcpy(dest, &data[1], byte_count);
    
    return MODBUS_OK;
}

/* 读保持寄存器(0x03) */
ModbusError Modbus_ReadHoldingRegisters(ModbusContext* ctx, uint8_t slave_addr, 
                                       uint16_t start_addr, uint16_t quantity, uint16_t* dest) {
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* data;
    uint32_t data_length;
    ModbusError error;
    uint32_t i;
    
    if (!ctx || !dest || quantity == 0 || quantity > 125) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_READ_HOLDING_REGISTERS, start_addr, quantity, NULL, 0, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_READ_HOLDING_REGISTERS || data_length < 1) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    uint8_t byte_count = data[0];
    if (data_length != (byte_count + 1) || (byte_count != (quantity * 2))) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 转换数据格式(大端序) */
    for (i = 0; i < quantity; i++) {
        dest[i] = (data[1 + i*2] << 8) | data[1 + i*2 + 1];
    }
    
    return MODBUS_OK;
}

/* 读输入寄存器(0x04) */
ModbusError Modbus_ReadInputRegisters(ModbusContext* ctx, uint8_t slave_addr, 
                                      uint16_t start_addr, uint16_t quantity, uint16_t* dest) {
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* data;
    uint32_t data_length;
    ModbusError error;
    uint32_t i;
    
    if (!ctx || !dest || quantity == 0 || quantity > 125) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_READ_INPUT_REGISTERS, start_addr, quantity, NULL, 0, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_READ_INPUT_REGISTERS || data_length < 1) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    uint8_t byte_count = data[0];
    if (data_length != (byte_count + 1) || (byte_count != (quantity * 2))) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 转换数据格式(大端序) */
    for (i = 0; i < quantity; i++) {
        dest[i] = (data[1 + i*2] << 8) | data[1 + i*2 + 1];
    }
    
    return MODBUS_OK;
}

/* 写单个线圈(0x05) */
ModbusError Modbus_WriteSingleCoil(ModbusContext* ctx, uint8_t slave_addr, 
                                  uint16_t addr, bool value) {
    uint8_t data[2];
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* response_data;
    uint32_t data_length;
    ModbusError error;
    
    if (!ctx) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 准备数据 */
    data[0] = (value) ? 0xFF : 0x00;
    data[1] = 0x00;
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_WRITE_SINGLE_COIL, addr, 0, data, 2, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &response_data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_WRITE_SINGLE_COIL || data_length != 4) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 验证响应中的地址和值 */
    uint16_t resp_addr = (response_data[0] << 8) | response_data[1];
    uint16_t resp_value = (response_data[2] << 8) | response_data[3];
    
    if (resp_addr != addr || ((resp_value == 0xFF00) != value)) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    return MODBUS_OK;
}

/* 写单个寄存器(0x06) */
ModbusError Modbus_WriteSingleRegister(ModbusContext* ctx, uint8_t slave_addr, 
                                      uint16_t addr, uint16_t value) {
    uint8_t data[2];
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* response_data;
    uint32_t data_length;
    ModbusError error;
    
    if (!ctx) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 准备数据 */
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_WRITE_SINGLE_REGISTER, addr, 0, data, 2, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &response_data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_WRITE_SINGLE_REGISTER || data_length != 4) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 验证响应中的地址和值 */
    uint16_t resp_addr = (response_data[0] << 8) | response_data[1];
    uint16_t resp_value = (response_data[2] << 8) | response_data[3];
    
    if (resp_addr != addr || resp_value != value) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    return MODBUS_OK;
}

/* 写多个线圈(0x0F) */
ModbusError Modbus_WriteMultipleCoils(ModbusContext* ctx, uint8_t slave_addr, 
                                     uint16_t start_addr, uint16_t quantity, const uint8_t* src) {
    uint8_t data[256];
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* response_data;
    uint32_t data_length;
    ModbusError error;
    uint8_t byte_count;
    
    if (!ctx || !src || quantity == 0 || quantity > 1968) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 计算字节数 */
    byte_count = (quantity + 7) / 8;
    
    if (byte_count > sizeof(data) - 3) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 准备数据 */
    data[0] = (start_addr >> 8) & 0xFF;
    data[1] = start_addr & 0xFF;
    data[2] = (quantity >> 8) & 0xFF;
    data[3] = quantity & 0xFF;
    data[4] = byte_count;
    
    memcpy(&data[5], src, byte_count);
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_WRITE_MULTIPLE_COILS, 0, 0, data, byte_count + 5, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &response_data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_WRITE_MULTIPLE_COILS || data_length != 4) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 验证响应中的地址和数量 */
    uint16_t resp_addr = (response_data[0] << 8) | response_data[1];
    uint16_t resp_quantity = (response_data[2] << 8) | response_data[3];
    
    if (resp_addr != start_addr || resp_quantity != quantity) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    return MODBUS_OK;
}

/* 写多个寄存器(0x10) */
ModbusError Modbus_WriteMultipleRegisters(ModbusContext* ctx, uint8_t slave_addr, 
                                         uint16_t start_addr, uint16_t quantity, const uint16_t* src) {
    uint8_t data[256];
    uint32_t response_length;
    uint8_t func_code;
    uint8_t* response_data;
    uint32_t data_length;
    ModbusError error;
    uint8_t byte_count;
    uint16_t i;
    
    if (!ctx || !src || quantity == 0 || quantity > 123) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 计算字节数 */
    byte_count = quantity * 2;
    
    if (byte_count > sizeof(data) - 3) {
        return MODBUS_ERROR_PARAM;
    }
    
    /* 准备数据 */
    data[0] = (start_addr >> 8) & 0xFF;
    data[1] = start_addr & 0xFF;
    data[2] = (quantity >> 8) & 0xFF;
    data[3] = quantity & 0xFF;
    data[4] = byte_count;
    
    /* 转换数据格式(大端序) */
    for (i = 0; i < quantity; i++) {
        data[5 + i*2] = (src[i] >> 8) & 0xFF;
        data[5 + i*2 + 1] = src[i] & 0xFF;
    }
    
    /* 发送请求 */
    error = modbus_send_request(ctx, slave_addr, MB_FC_WRITE_MULTIPLE_REGISTERS, 0, 0, data, byte_count + 5, &response_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    /* 解析响应 */
    error = modbus_parse_response(ctx, response_length, &func_code, &response_data, &data_length);
    if (error != MODBUS_OK) {
        return error;
    }
    
    if (func_code != MB_FC_WRITE_MULTIPLE_REGISTERS || data_length != 4) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    /* 验证响应中的地址和数量 */
    uint16_t resp_addr = (response_data[0] << 8) | response_data[1];
    uint16_t resp_quantity = (response_data[2] << 8) | response_data[3];
    
    if (resp_addr != start_addr || resp_quantity != quantity) {
        return MODBUS_ERROR_PROTOCOL;
    }
    
    return MODBUS_OK;
}

/* 处理Modbus请求(服务器端) */
ModbusError Modbus_ProcessRequest(ModbusContext* ctx, 
                                 uint8_t* response, uint32_t* response_length) {
    (void)ctx;
    (void)response;
    (void)response_length;
    
    /* 服务器端实现留空,需要根据具体应用场景实现 */
    return MODBUS_ERROR_PARAM;
}

/* 获取错误信息字符串 */
const char* Modbus_GetErrorString(ModbusError error) {
    if (error < 0 || error >= (sizeof(error_messages) / sizeof(error_messages[0]))) {
        return "Unknown error";
    }
    
    return error_messages[error];
}

/* 获取异常信息字符串 */
const char* Modbus_GetExceptionString(ModbusExceptionCode exception) {
    if (exception < 1 || exception >= (sizeof(exception_messages) / sizeof(exception_messages[0]))) {
        return "Unknown exception";
    }
    
    return exception_messages[exception];
}

库使用方法

下面是一个使用该库的简单示例:

/* Modbus客户端使用示例 */
#include "modbus.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 硬件接口函数实现 */
static int uart_send(const uint8_t* data, uint32_t length, void* context) {
    /* 实现串口发送功能 */
    (void)context;
    /* 示例实现,实际应用中需替换为实际的串口发送代码 */
    printf("发送数据: ");
    for (uint32_t i = 0; i < length; i++) {
        printf("%02X ", data[i]);
    }
    printf("\n");
    return (int)length;
}

static int uart_receive(uint8_t* data, uint32_t max_length, uint32_t timeout_ms, void* context) {
    /* 实现串口接收功能 */
    (void)context;
    (void)timeout_ms;
    /* 示例实现,实际应用中需替换为实际的串口接收代码 */
    printf("接收数据: (模拟数据)\n");
    static const uint8_t test_data[] = {0x01, 0x03, 0x04, 0x00, 0x01, 0x00, 0x02, 0xXX, 0xXX};
    uint32_t length = sizeof(test_data) - 2;  /* 减去CRC */
    if (length > max_length) {
        length = max_length;
    }
    memcpy(data, test_data, length);
    return (int)length;
}

int main() {
    ModbusContext ctx;
    uint8_t rx_buffer[256];
    uint16_t registers[10];
    ModbusError error;
    
    /* 初始化Modbus上下文 */
    error = Modbus_Init(&ctx, MB_RTU, 0x01, uart_send, uart_receive, NULL, rx_buffer, sizeof(rx_buffer));
    if (error != MODBUS_OK) {
        printf("Modbus初始化失败: %s\n", Modbus_GetErrorString(error));
        return -1;
    }
    
    /* 连接Modbus设备 */
    error = Modbus_Connect(&ctx);
    if (error != MODBUS_OK) {
        printf("Modbus连接失败: %s\n", Modbus_GetErrorString(error));
        return -1;
    }
    
    /* 读保持寄存器 */
    error = Modbus_ReadHoldingRegisters(&ctx, 0x01, 0x0000, 2, registers);
    if (error != MODBUS_OK) {
        printf("读保持寄存器失败: %s\n", Modbus_GetErrorString(error));
    } else {
        printf("读保持寄存器成功:\n");
        printf("寄存器0: %u\n", registers[0]);
        printf("寄存器1: %u\n", registers[1]);
    }
    
    /* 写单个寄存器 */
    error = Modbus_WriteSingleRegister(&ctx, 0x01, 0x0000, 0x1234);
    if (error != MODBUS_OK) {
        printf("写单个寄存器失败: %s\n", Modbus_GetErrorString(error));
    } else {
        printf("写单个寄存器成功\n");
    }
    
    /* 断开连接 */
    Modbus_Disconnect(&ctx);
    
    return 0;
}

扩展建议

  1. 添加更多功能码支持:目前只实现了常用的功能码,可以根据需要添加更多功能码支持
  2. 增强服务器端功能:完善Modbus_ProcessRequest函数,实现完整的服务器端功能
  3. 添加异步操作支持:实现非阻塞 API,支持多线程环境
  4. 优化性能:针对特定硬件平台进行性能优化
  5. 增加调试功能:添加详细的调试日志功能

这个 Modbus 库设计简洁,易于扩展,适合在嵌入式系统中使用。根据实际需求,你可以进一步扩展其功能,如添加更多功能码支持、增强服务器端功能等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

start_up_go

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值