Modbus协议C语言实现(易于移植版本)

易于移植的Modbus协议栈的C语言实现,支持RTU和ASCII模式,包含主机(Master)和从机(Slave)功能。

头文件 (modbus.h)

c 复制代码
#ifndef MODBUS_H
#define MODBUS_H

#include <stdint.h>
#include <stddef.h>

// 模式定义
typedef enum {
    MODBUS_RTU,
    MODBUS_ASCII
} modbus_mode_t;

// 错误代码
typedef enum {
    MODBUS_SUCCESS = 0,
    MODBUS_ERROR_INVALID_SLAVE,
    MODBUS_ERROR_INVALID_FUNCTION,
    MODBUS_ERROR_INVALID_DATA,
    MODBUS_ERROR_SLAVE_DEVICE_FAILURE,
    MODBUS_ERROR_CRC,
    MODBUS_ERROR_TIMEOUT,
    MODBUS_ERROR_MEMORY
} modbus_error_t;

// 功能码定义
typedef enum {
    MODBUS_FC_READ_COILS = 0x01,
    MODBUS_FC_READ_DISCRETE_INPUTS = 0x02,
    MODBUS_FC_READ_HOLDING_REGISTERS = 0x03,
    MODBUS_FC_READ_INPUT_REGISTERS = 0x04,
    MODBUS_FC_WRITE_SINGLE_COIL = 0x05,
    MODBUS_FC_WRITE_SINGLE_REGISTER = 0x06,
    MODBUS_FC_WRITE_MULTIPLE_COILS = 0x0F,
    MODBUS_FC_WRITE_MULTIPLE_REGISTERS = 0x10
} modbus_function_code_t;

// Modbus从设备回调函数类型
typedef modbus_error_t (*modbus_read_coil_cb_t)(uint16_t address, uint8_t* value);
typedef modbus_error_t (*modbus_read_discrete_input_cb_t)(uint16_t address, uint8_t* value);
typedef modbus_error_t (*modbus_read_holding_register_cb_t)(uint16_t address, uint16_t* value);
typedef modbus_error_t (*modbus_read_input_register_cb_t)(uint16_t address, uint16_t* value);
typedef modbus_error_t (*modbus_write_coil_cb_t)(uint16_t address, uint8_t value);
typedef modbus_error_t (*modbus_write_register_cb_t)(uint16_t address, uint16_t value);
typedef modbus_error_t (*modbus_write_multiple_coils_cb_t)(uint16_t start_address, uint16_t quantity, const uint8_t* values);
typedef modbus_error_t (*modbus_write_multiple_registers_cb_t)(uint16_t start_address, uint16_t quantity, const uint16_t* values);

// Modbus从设备回调结构体
typedef struct {
    modbus_read_coil_cb_t read_coil;
    modbus_read_discrete_input_cb_t read_discrete_input;
    modbus_read_holding_register_cb_t read_holding_register;
    modbus_read_input_register_cb_t read_input_register;
    modbus_write_coil_cb_t write_coil;
    modbus_write_register_cb_t write_register;
    modbus_write_multiple_coils_cb_t write_multiple_coils;
    modbus_write_multiple_registers_cb_t write_multiple_registers;
} modbus_callbacks_t;

// Modbus上下文结构
typedef struct {
    uint8_t address;                // 设备地址
    modbus_mode_t mode;             // RTU或ASCII模式
    modbus_callbacks_t callbacks;   // 回调函数
    void* user_data;                // 用户数据
} modbus_t;

// 平台相关函数(需要用户实现)
typedef struct {
    // 发送数据
    int (*send)(const uint8_t* data, size_t length, void* user_data);
    // 接收数据(带超时)
    int (*receive)(uint8_t* data, size_t max_length, uint32_t timeout_ms, void* user_data);
    // 获取当前时间(毫秒)
    uint32_t (*get_time_ms)(void);
    // 延时函数(毫秒)
    void (*delay_ms)(uint32_t ms);
} modbus_platform_t;

// 初始化Modbus上下文
modbus_error_t modbus_init(modbus_t* ctx, uint8_t address, modbus_mode_t mode, 
                          const modbus_callbacks_t* callbacks, void* user_data);

// 设置平台相关函数
void modbus_set_platform(modbus_platform_t* platform);

// 主设备函数
modbus_error_t modbus_read_coils(modbus_t* ctx, uint8_t slave_address, 
                                uint16_t start_address, uint16_t quantity, 
                                uint8_t* values);
modbus_error_t modbus_read_discrete_inputs(modbus_t* ctx, uint8_t slave_address, 
                                          uint16_t start_address, uint16_t quantity, 
                                          uint8_t* values);
modbus_error_t modbus_read_holding_registers(modbus_t* ctx, uint8_t slave_address, 
                                            uint16_t start_address, uint16_t quantity, 
                                            uint16_t* values);
modbus_error_t modbus_read_input_registers(modbus_t* ctx, uint8_t slave_address, 
                                          uint16_t start_address, uint16_t quantity, 
                                          uint16_t* values);
modbus_error_t modbus_write_single_coil(modbus_t* ctx, uint8_t slave_address, 
                                       uint16_t address, uint8_t value);
modbus_error_t modbus_write_single_register(modbus_t* ctx, uint8_t slave_address, 
                                           uint16_t address, uint16_t value);
modbus_error_t modbus_write_multiple_coils(modbus_t* ctx, uint8_t slave_address, 
                                          uint16_t start_address, uint16_t quantity, 
                                          const uint8_t* values);
modbus_error_t modbus_write_multiple_registers(modbus_t* ctx, uint8_t slave_address, 
                                              uint16_t start_address, uint16_t quantity, 
                                              const uint16_t* values);

// 从设备处理函数
modbus_error_t modbus_process_request(modbus_t* ctx);

// CRC计算函数
uint16_t modbus_crc16(const uint8_t* data, size_t length);

// LRC计算函数(用于ASCII模式)
uint8_t modbus_lrc(const uint8_t* data, size_t length);

// 辅助函数
uint16_t modbus_bytes_to_uint16(const uint8_t* bytes);
void modbus_uint16_to_bytes(uint16_t value, uint8_t* bytes);

#endif // MODBUS_H

实现文件 (modbus.c)

c 复制代码
#include "modbus.h"
#include <string.h>

// 平台相关函数
static modbus_platform_t platform;

// 设置平台相关函数
void modbus_set_platform(modbus_platform_t* platform_functions) {
    if (platform_functions) {
        platform = *platform_functions;
    }
}

// 初始化Modbus上下文
modbus_error_t modbus_init(modbus_t* ctx, uint8_t address, modbus_mode_t mode, 
                          const modbus_callbacks_t* callbacks, void* user_data) {
    if (!ctx) {
        return MODBUS_ERROR_INVALID_DATA;
    }
    
    ctx->address = address;
    ctx->mode = mode;
    ctx->user_data = user_data;
    
    if (callbacks) {
        ctx->callbacks = *callbacks;
    } else {
        // 清空回调函数
        memset(&ctx->callbacks, 0, sizeof(modbus_callbacks_t));
    }
    
    return MODBUS_SUCCESS;
}

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

// LRC计算 (用于ASCII模式)
uint8_t modbus_lrc(const uint8_t* data, size_t length) {
    uint8_t lrc = 0;
    
    for (size_t i = 0; i < length; i++) {
        lrc += data[i];
    }
    
    return (uint8_t)(-((int8_t)lrc));
}

// 字节数组转换为16位整数
uint16_t modbus_bytes_to_uint16(const uint8_t* bytes) {
    return (bytes[0] << 8) | bytes[1];
}

// 16位整数转换为字节数组
void modbus_uint16_to_bytes(uint16_t value, uint8_t* bytes) {
    bytes[0] = (value >> 8) & 0xFF;
    bytes[1] = value & 0xFF;
}

// 发送响应
static modbus_error_t send_response(modbus_t* ctx, const uint8_t* data, size_t length) {
    if (!platform.send) {
        return MODBUS_ERROR_INVALID_DATA;
    }
    
    if (ctx->mode == MODBUS_RTU) {
        // RTU模式:直接发送数据+CRC
        uint8_t buffer[length + 2];
        memcpy(buffer, data, length);
        
        uint16_t crc = modbus_crc16(data, length);
        buffer[length] = crc & 0xFF;
        buffer[length + 1] = (crc >> 8) & 0xFF;
        
        return platform.send(buffer, length + 2, ctx->user_data) == (int)(length + 2) ? 
               MODBUS_SUCCESS : MODBUS_ERROR_MEMORY;
    } else {
        // ASCII模式:添加起始符、LRC和结束符
        uint8_t lrc = modbus_lrc(data, length);
        uint8_t ascii_buffer[2 * (length + 1) + 3]; // 数据转ASCII + LRC + 起始结束符
        
        ascii_buffer[0] = ':';
        size_t idx = 1;
        
        // 转换数据到ASCII
        for (size_t i = 0; i < length; i++) {
            uint8_t nibble_high = (data[i] >> 4) & 0x0F;
            uint8_t nibble_low = data[i] & 0x0F;
            
            ascii_buffer[idx++] = (nibble_high < 10) ? ('0' + nibble_high) : ('A' + nibble_high - 10);
            ascii_buffer[idx++] = (nibble_low < 10) ? ('0' + nibble_low) : ('A' + nibble_low - 10);
        }
        
        // 添加LRC
        uint8_t lrc_high = (lrc >> 4) & 0x0F;
        uint8_t lrc_low = lrc & 0x0F;
        
        ascii_buffer[idx++] = (lrc_high < 10) ? ('0' + lrc_high) : ('A' + lrc_high - 10);
        ascii_buffer[idx++] = (lrc_low < 10) ? ('0' + lrc_low) : ('A' + lrc_low - 10);
        
        // 添加结束符
        ascii_buffer[idx++] = '\r';
        ascii_buffer[idx++] = '\n';
        
        return platform.send(ascii_buffer, idx, ctx->user_data) == (int)idx ? 
               MODBUS_SUCCESS : MODBUS_ERROR_MEMORY;
    }
}

// 发送异常响应
static modbus_error_t send_exception_response(modbus_t* ctx, uint8_t function_code, uint8_t exception_code) {
    uint8_t response[2];
    response[0] = function_code | 0x80; // 设置最高位表示异常
    response[1] = exception_code;
    
    return send_response(ctx, response, 2);
}

// 处理读取线圈请求
static modbus_error_t handle_read_coils(modbus_t* ctx, const uint8_t* request, size_t length) {
    if (length < 4 || !ctx->callbacks.read_coil) {
        return send_exception_response(ctx, MODBUS_FC_READ_COILS, 0x03); // 非法数据值
    }
    
    uint16_t start_address = modbus_bytes_to_uint16(request);
    uint16_t quantity = modbus_bytes_to_uint16(request + 2);
    
    if (quantity < 1 || quantity > 2000) {
        return send_exception_response(ctx, MODBUS_FC_READ_COILS, 0x03); // 非法数据值
    }
    
    uint8_t response[2 + (quantity + 7) / 8]; // 字节数 + 数据
    response[0] = MODBUS_FC_READ_COILS;
    response[1] = (quantity + 7) / 8; // 字节数
    
    // 读取所有请求的线圈
    for (uint16_t i = 0; i < quantity; i++) {
        uint8_t value;
        modbus_error_t err = ctx->callbacks.read_coil(start_address + i, &value);
        
        if (err != MODBUS_SUCCESS) {
            return send_exception_response(ctx, MODBUS_FC_READ_COILS, 0x04); // 从设备故障
        }
        
        if (value) {
            response[2 + i / 8] |= (1 << (i % 8));
        } else {
            response[2 + i / 8] &= ~(1 << (i % 8));
        }
    }
    
    return send_response(ctx, response, 2 + response[1]);
}

// 处理读取保持寄存器请求
static modbus_error_t handle_read_holding_registers(modbus_t* ctx, const uint8_t* request, size_t length) {
    if (length < 4 || !ctx->callbacks.read_holding_register) {
        return send_exception_response(ctx, MODBUS_FC_READ_HOLDING_REGISTERS, 0x03); // 非法数据值
    }
    
    uint16_t start_address = modbus_bytes_to_uint16(request);
    uint16_t quantity = modbus_bytes_to_uint16(request + 2);
    
    if (quantity < 1 || quantity > 125) {
        return send_exception_response(ctx, MODBUS_FC_READ_HOLDING_REGISTERS, 0x03); // 非法数据值
    }
    
    uint8_t response[2 + quantity * 2]; // 字节数 + 数据
    response[0] = MODBUS_FC_READ_HOLDING_REGISTERS;
    response[1] = quantity * 2; // 字节数
    
    // 读取所有请求的寄存器
    for (uint16_t i = 0; i < quantity; i++) {
        uint16_t value;
        modbus_error_t err = ctx->callbacks.read_holding_register(start_address + i, &value);
        
        if (err != MODBUS_SUCCESS) {
            return send_exception_response(ctx, MODBUS_FC_READ_HOLDING_REGISTERS, 0x04); // 从设备故障
        }
        
        modbus_uint16_to_bytes(value, response + 2 + i * 2);
    }
    
    return send_response(ctx, response, 2 + quantity * 2);
}

// 处理写入单个寄存器请求
static modbus_error_t handle_write_single_register(modbus_t* ctx, const uint8_t* request, size_t length) {
    if (length < 4 || !ctx->callbacks.write_register) {
        return send_exception_response(ctx, MODBUS_FC_WRITE_SINGLE_REGISTER, 0x03); // 非法数据值
    }
    
    uint16_t address = modbus_bytes_to_uint16(request);
    uint16_t value = modbus_bytes_to_uint16(request + 2);
    
    modbus_error_t err = ctx->callbacks.write_register(address, value);
    
    if (err != MODBUS_SUCCESS) {
        return send_exception_response(ctx, MODBUS_FC_WRITE_SINGLE_REGISTER, 0x04); // 从设备故障
    }
    
    // 响应与请求相同
    uint8_t response[5];
    response[0] = MODBUS_FC_WRITE_SINGLE_REGISTER;
    memcpy(response + 1, request, 4);
    
    return send_response(ctx, response, 5);
}

// 处理写入多个寄存器请求
static modbus_error_t handle_write_multiple_registers(modbus_t* ctx, const uint8_t* request, size_t length) {
    if (length < 5 || !ctx->callbacks.write_multiple_registers) {
        return send_exception_response(ctx, MODBUS_FC_WRITE_MULTIPLE_REGISTERS, 0x03); // 非法数据值
    }
    
    uint16_t start_address = modbus_bytes_to_uint16(request);
    uint16_t quantity = modbus_bytes_to_uint16(request + 2);
    uint8_t byte_count = request[4];
    
    if (quantity < 1 || quantity > 123 || byte_count != quantity * 2) {
        return send_exception_response(ctx, MODBUS_FC_WRITE_MULTIPLE_REGISTERS, 0x03); // 非法数据值
    }
    
    // 提取寄存器值
    uint16_t values[quantity];
    for (uint16_t i = 0; i < quantity; i++) {
        values[i] = modbus_bytes_to_uint16(request + 5 + i * 2);
    }
    
    modbus_error_t err = ctx->callbacks.write_multiple_registers(start_address, quantity, values);
    
    if (err != MODBUS_SUCCESS) {
        return send_exception_response(ctx, MODBUS_FC_WRITE_MULTIPLE_REGISTERS, 0x04); // 从设备故障
    }
    
    // 响应包含起始地址和数量
    uint8_t response[5];
    response[0] = MODBUS_FC_WRITE_MULTIPLE_REGISTERS;
    memcpy(response + 1, request, 4);
    
    return send_response(ctx, response, 5);
}

// 从设备处理请求
modbus_error_t modbus_process_request(modbus_t* ctx) {
    if (!platform.receive || !ctx) {
        return MODBUS_ERROR_INVALID_DATA;
    }
    
    uint8_t buffer[256];
    int received;
    
    if (ctx->mode == MODBUS_RTU) {
        // RTU模式接收
        received = platform.receive(buffer, sizeof(buffer), 100, ctx->user_data);
        
        if (received < 4) { // 最小帧长度:地址+功能码+CRC(2字节)
            return MODBUS_ERROR_TIMEOUT;
        }
        
        // 验证CRC
        uint16_t crc_received = (buffer[received - 1] << 8) | buffer[received - 2];
        uint16_t crc_calculated = modbus_crc16(buffer, received - 2);
        
        if (crc_received != crc_calculated) {
            return MODBUS_ERROR_CRC;
        }
        
        // 检查地址是否匹配
        if (buffer[0] != ctx->address && buffer[0] != 0) { // 0是广播地址
            return MODBUS_ERROR_INVALID_SLAVE;
        }
        
        // 处理请求(去掉CRC)
        received -= 2;
    } else {
        // ASCII模式接收
        received = platform.receive(buffer, sizeof(buffer), 100, ctx->user_data);
        
        if (received < 3 || buffer[0] != ':') { // 最小帧长度:: + 至少1字节数据 + LRC + CRLF
            return MODBUS_ERROR_TIMEOUT;
        }
        
        // 查找结束符
        int end_pos = -1;
        for (int i = 1; i < received - 1; i++) {
            if (buffer[i] == '\r' && buffer[i + 1] == '\n') {
                end_pos = i;
                break;
            }
        }
        
        if (end_pos == -1) {
            return MODBUS_ERROR_INVALID_DATA;
        }
        
        // 转换ASCII到二进制
        uint8_t binary_buffer[256];
        int binary_length = 0;
        
        for (int i = 1; i < end_pos; i += 2) {
            if (i + 1 >= end_pos) {
                return MODBUS_ERROR_INVALID_DATA;
            }
            
            uint8_t high_nibble = buffer[i];
            uint8_t low_nibble = buffer[i + 1];
            
            if (high_nibble >= '0' && high_nibble <= '9') {
                high_nibble -= '0';
            } else if (high_nibble >= 'A' && high_nibble <= 'F') {
                high_nibble -= 'A' - 10;
            } else if (high_nibble >= 'a' && high_nibble <= 'f') {
                high_nibble -= 'a' - 10;
            } else {
                return MODBUS_ERROR_INVALID_DATA;
            }
            
            if (low_nibble >= '0' && low_nibble <= '9') {
                low_nibble -= '0';
            } else if (low_nibble >= 'A' && low_nibble <= 'F') {
                low_nibble -= 'A' - 10;
            } else if (low_nibble >= 'a' && low_nibble <= 'f') {
                low_nibble -= 'a' - 10;
            } else {
                return MODBUS_ERROR_INVALID_DATA;
            }
            
            binary_buffer[binary_length++] = (high_nibble << 4) | low_nibble;
        }
        
        // 验证LRC
        uint8_t lrc_received = binary_buffer[binary_length - 1];
        uint8_t lrc_calculated = modbus_lrc(binary_buffer, binary_length - 1);
        
        if (lrc_received != lrc_calculated) {
            return MODBUS_ERROR_CRC;
        }
        
        // 检查地址是否匹配
        if (binary_buffer[0] != ctx->address && binary_buffer[0] != 0) { // 0是广播地址
            return MODBUS_ERROR_INVALID_SLAVE;
        }
        
        // 使用二进制数据(去掉LRC)
        memcpy(buffer, binary_buffer, binary_length - 1);
        received = binary_length - 1;
    }
    
    // 处理功能码
    uint8_t function_code = buffer[1];
    
    switch (function_code) {
        case MODBUS_FC_READ_COILS:
            return handle_read_coils(ctx, buffer + 2, received - 2);
            
        case MODBUS_FC_READ_HOLDING_REGISTERS:
            return handle_read_holding_registers(ctx, buffer + 2, received - 2);
            
        case MODBUS_FC_WRITE_SINGLE_REGISTER:
            return handle_write_single_register(ctx, buffer + 2, received - 2);
            
        case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
            return handle_write_multiple_registers(ctx, buffer + 2, received - 2);
            
        default:
            return send_exception_response(ctx, function_code, 0x01); // 非法功能
    }
}

// 主设备函数实现
modbus_error_t modbus_read_holding_registers(modbus_t* ctx, uint8_t slave_address, 
                                            uint16_t start_address, uint16_t quantity, 
                                            uint16_t* values) {
    if (!platform.send || !platform.receive || !ctx || !values) {
        return MODBUS_ERROR_INVALID_DATA;
    }
    
    if (quantity < 1 || quantity > 125) {
        return MODBUS_ERROR_INVALID_DATA;
    }
    
    // 构建请求
    uint8_t request[5];
    request[0] = slave_address;
    request[1] = MODBUS_FC_READ_HOLDING_REGISTERS;
    modbus_uint16_to_bytes(start_address, request + 2);
    modbus_uint16_to_bytes(quantity, request + 4);
    
    // 发送请求
    modbus_error_t err;
    if (ctx->mode == MODBUS_RTU) {
        uint16_t crc = modbus_crc16(request, 5);
        uint8_t full_request[7];
        memcpy(full_request, request, 5);
        full_request[5] = crc & 0xFF;
        full_request[6] = (crc >> 8) & 0xFF;
        
        err = platform.send(full_request, 7, ctx->user_data) == 7 ? 
              MODBUS_SUCCESS : MODBUS_ERROR_MEMORY;
    } else {
        // ASCII模式实现类似,需要转换
        err = MODBUS_ERROR_INVALID_DATA; // 简化实现
    }
    
    if (err != MODBUS_SUCCESS) {
        return err;
    }
    
    // 接收响应
    uint8_t response[256];
    int received = platform.receive(response, sizeof(response), 1000, ctx->user_data);
    
    if (received < 5) {
        return MODBUS_ERROR_TIMEOUT;
    }
    
    // 验证响应(简化实现)
    if (response[0] != slave_address || response[1] != MODBUS_FC_READ_HOLDING_REGISTERS) {
        return MODBUS_ERROR_INVALID_DATA;
    }
    
    uint8_t byte_count = response[2];
    if (byte_count != quantity * 2) {
        return MODBUS_ERROR_INVALID_DATA;
    }
    
    // 提取数据
    for (int i = 0; i < quantity; i++) {
        values[i] = modbus_bytes_to_uint16(response + 3 + i * 2);
    }
    
    return MODBUS_SUCCESS;
}

// 其他主设备函数实现类似,为简洁起见省略
// modbus_write_single_register, modbus_write_multiple_registers等

// 简化实现其他函数
modbus_error_t modbus_read_coils(modbus_t* ctx, uint8_t slave_address, 
                                uint16_t start_address, uint16_t quantity, 
                                uint8_t* values) {
    // 实现类似于modbus_read_holding_registers
    return MODBUS_ERROR_INVALID_FUNCTION; // 简化
}

modbus_error_t modbus_write_single_register(modbus_t* ctx, uint8_t slave_address, 
                                           uint16_t address, uint16_t value) {
    // 实现类似于modbus_read_holding_registers
    return MODBUS_ERROR_INVALID_FUNCTION; // 简化
}

// 其他函数实现...

使用示例

1. 平台相关函数实现示例

c 复制代码
#include "modbus.h"
#include <stdio.h>

// 假设的串口实现
typedef struct {
    int fd; // 文件描述符或句柄
} serial_port_t;

// 发送数据函数
int serial_send(const uint8_t* data, size_t length, void* user_data) {
    serial_port_t* port = (serial_port_t*)user_data;
    // 实现串口发送
    printf("Sending %zu bytes\n", length);
    return length; // 返回实际发送的字节数
}

// 接收数据函数
int serial_receive(uint8_t* data, size_t max_length, uint32_t timeout_ms, void* user_data) {
    serial_port_t* port = (serial_port_t*)user_data;
    // 实现带超时的串口接收
    // 这里是简化实现
    static int counter = 0;
    if (counter++ < 3) return 0; // 模拟没有数据
    
    // 模拟接收到的数据
    data[0] = 0x01; // 地址
    data[1] = 0x03; // 功能码
    data[2] = 0x04; // 字节数
    data[3] = 0x00; // 数据高字节
    data[4] = 0x01; // 数据低字节
    data[5] = 0x00; // 数据高字节
    data[6] = 0x02; // 数据低字节
    data[7] = 0x00; // CRC低字节
    data[8] = 0x00; // CRC高字节
    
    return 9; // 返回实际接收的字节数
}

// 获取时间函数
uint32_t get_time_ms(void) {
    // 实现获取当前时间(毫秒)
    static uint32_t time = 0;
    return time += 10; // 模拟时间递增
}

// 延时函数
void delay_ms(uint32_t ms) {
    // 实现毫秒级延时
    printf("Delay %u ms\n", ms);
}

// 从设备回调函数示例
modbus_error_t read_holding_register_cb(uint16_t address, uint16_t* value) {
    // 模拟读取保持寄存器
    if (address == 0) {
        *value = 0x1234;
    } else if (address == 1) {
        *value = 0x5678;
    } else {
        return MODBUS_ERROR_INVALID_DATA;
    }
    return MODBUS_SUCCESS;
}

modbus_error_t write_register_cb(uint16_t address, uint16_t value) {
    // 模拟写入寄存器
    printf("Write register %d = %d\n", address, value);
    return MODBUS_SUCCESS;
}

int main() {
    // 初始化平台函数
    modbus_platform_t platform = {
        .send = serial_send,
        .receive = serial_receive,
        .get_time_ms = get_time_ms,
        .delay_ms = delay_ms
    };
    modbus_set_platform(&platform);
    
    // 初始化串口
    serial_port_t port = {0};
    
    // 初始化Modbus从设备
    modbus_callbacks_t callbacks = {
        .read_holding_register = read_holding_register_cb,
        .write_register = write_register_cb
    };
    
    modbus_t slave;
    modbus_init(&slave, 0x01, MODBUS_RTU, &callbacks, &port);
    
    // 处理请求
    modbus_process_request(&slave);
    
    // 初始化Modbus主设备
    modbus_t master;
    modbus_init(&master, 0x00, MODBUS_RTU, NULL, &port);
    
    // 读取保持寄存器
    uint16_t values[2];
    modbus_error_t err = modbus_read_holding_registers(&master, 0x01, 0, 2, values);
    
    if (err == MODBUS_SUCCESS) {
        printf("Read values: 0x%04X, 0x%04X\n", values[0], values[1]);
    } else {
        printf("Error: %d\n", err);
    }
    
    return 0;
}

2. 集成到嵌入式系统

c 复制代码
// 在RTOS任务中处理Modbus请求
void modbus_task(void* argument) {
    serial_port_t* port = (serial_port_t*)argument;
    
    // 初始化Modbus
    modbus_callbacks_t callbacks = {
        .read_holding_register = read_holding_register_cb,
        .write_register = write_register_cb
        // 设置其他回调函数...
    };
    
    modbus_t ctx;
    modbus_init(&ctx, 0x01, MODBUS_RTU, &callbacks, port);
    
    while (1) {
        modbus_error_t err = modbus_process_request(&ctx);
        
        if (err != MODBUS_SUCCESS && err != MODBUS_ERROR_TIMEOUT) {
            // 处理错误
            printf("Modbus error: %d\n", err);
        }
        
        // 任务延时
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

参考代码 modbus完整协议使用C语言编写易于移植 www.3dddown.com/csa/51670.html

移植指南

  1. 平台相关函数

    • 实现modbus_platform_t中定义的四个函数:
      • send: 数据发送函数
      • receive: 带超时的数据接收函数
      • get_time_ms: 获取当前时间(毫秒)
      • delay_ms: 毫秒级延时函数
  2. 内存分配

    • 本实现不使用动态内存分配,适合嵌入式系统
    • 所有缓冲区都是静态分配或栈分配
  3. 配置选项

    • 通过修改modbus_init参数配置设备地址和模式
    • 通过回调函数接口实现设备特定功能
  4. 资源需求

    • 代码大小:约4-8KB(取决于编译器和优化选项)
    • RAM:几百字节(取决于缓冲区大小)
    • 不需要操作系统支持,可在裸机环境中运行
  5. 性能优化

    • 对于高速应用,可以优化CRC计算(使用查表法)
    • 可以根据具体硬件优化串口通信

这个Modbus协议栈实现了RTU和ASCII模式,支持常用的功能码,并且设计为易于移植到各种平台。

相关推荐
Luna-player4 小时前
在前端中list.map的用法
前端·数据结构·list
听风吟丶4 小时前
Java 反射机制深度解析:从原理到实战应用与性能优化
java·开发语言·性能优化
一缕猫毛4 小时前
Flink demo代码
java·大数据·flink
用户47949283569154 小时前
面试官问 React Fiber,这一篇文章就够了
前端·javascript·react.js
小安同学iter5 小时前
天机学堂-优惠券功能-day09(七)
java·spring cloud·微服务·jenkins·优惠券·天机学堂
it_czz5 小时前
MCP调用流程图
java
Herbert_hwt5 小时前
C语言字符输入输出函数全解:从基础到实战应用
c语言
LYFlied5 小时前
【一句话概述】Webpack、Vite、Rollup 核心区别
前端·webpack·node.js·rollup·vite·打包·一句话概述
历程里程碑5 小时前
C++ 10 模板进阶:参数特化与分离编译解析
c语言·开发语言·数据结构·c++·算法