STM32F407 Modbus RTU主站例程

Modbus RTU主站实现,包含多从站管理、超时重发、错误处理、数据解析


一、系统架构

STM32F407 (Modbus主站)
     ↓
  USART2/3/6 (RS485)
     ↓
  MAX485收发器
     ↓
  Modbus从站网络
     ↓
  支持功能码:01, 02, 03, 04, 05, 06, 15, 16

核心特性

  • 多从站轮询(1-247)
  • 自动重发(1-3次)
  • CRC16校验
  • 响应超时检测
  • 异常响应处理
  • 多串口支持
  • 线程安全队列

二、硬件连接

1、RS485接口

STM32F407          MAX485
PA2 (USART2_TX)  → DI
PA3 (USART2_RX)  → RO
PA1 (DE/RE控制)  → DE, RE
                     ↓
                  A, B (RS485总线)

2、控制引脚配置

// DE/RE控制
#define RS485_DE_PORT    GPIOA
#define RS485_DE_PIN     GPIO_PIN_1

#define RS485_TX_MODE()  HAL_GPIO_WritePin(RS485_DE_PORT, RS485_DE_PIN, GPIO_PIN_SET)
#define RS485_RX_MODE()  HAL_GPIO_WritePin(RS485_DE_PORT, RS485_DE_PIN, GPIO_PIN_RESET)

三、程序架构

Modbus_Master/
├── modbus_master.h
├── modbus_master.c
├── modbus_crc.c
├── modbus_queue.c
├── modbus_rtu.c
└── main.c

四、Modbus主站核心实现

1、头文件定义

// modbus_master.h
#ifndef __MODBUS_MASTER_H
#define __MODBUS_MASTER_H

#include "stm32f4xx_hal.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"
#include <stdint.h>
#include <string.h>

// Modbus功能码
#define MODBUS_FC_READ_COILS          0x01
#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
#define MODBUS_FC_READ_HOLDING_REGS    0x03
#define MODBUS_FC_READ_INPUT_REGS      0x04
#define MODBUS_FC_WRITE_SINGLE_COIL    0x05
#define MODBUS_FC_WRITE_SINGLE_REG     0x06
#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
#define MODBUS_FC_WRITE_MULTIPLE_REGS  0x10
#define MODBUS_FC_READ_FILE_RECORD     0x14
#define MODBUS_FC_WRITE_FILE_RECORD    0x15
#define MODBUS_FC_MASK_WRITE_REG       0x16
#define MODBUS_FC_READ_WRITE_REGS      0x17

// Modbus异常码
#define MODBUS_EXCEPTION_ILLEGAL_FUNCTION        0x01
#define MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS    0x02
#define MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE      0x03
#define MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE    0x04
#define MODBUS_EXCEPTION_ACKNOWLEDGE             0x05
#define MODBUS_EXCEPTION_SLAVE_DEVICE_BUSY       0x06
#define MODBUS_EXCEPTION_MEMORY_PARITY_ERROR     0x08
#define MODBUS_EXCEPTION_GATEWAY_PATH_UNAVAILABLE 0x0A
#define MODBUS_EXCEPTION_GATEWAY_TARGET_NO_RESP  0x0B

// 错误码
typedef enum {
    MODBUS_OK = 0,
    MODBUS_ERR_TIMEOUT,
    MODBUS_ERR_CRC,
    MODBUS_ERR_EXCEPTION,
    MODBUS_ERR_RESP_LEN,
    MODBUS_ERR_SLAVE_ADDR,
    MODBUS_ERR_FUNC_CODE,
    MODBUS_ERR_QUEUE_FULL,
    MODBUS_ERR_BUSY,
    MODBUS_ERR_PORT
} Modbus_Error_t;

// 串口端口
typedef enum {
    MODBUS_PORT_1 = 0,  // USART1
    MODBUS_PORT_2,      // USART2
    MODBUS_PORT_3,      // USART3
    MODBUS_PORT_6       // USART6
} Modbus_Port_t;

// Modbus请求结构
typedef struct {
    uint8_t slave_addr;     // 从站地址
    uint8_t func_code;      // 功能码
    uint16_t reg_addr;      // 寄存器地址
    uint16_t quantity;      // 数量
    uint8_t *data;         // 数据指针
    uint16_t data_len;     // 数据长度
    uint32_t timeout_ms;   // 超时时间
    uint8_t retry_count;   // 重试次数
} Modbus_Request_t;

// Modbus响应结构
typedef struct {
    uint8_t slave_addr;     // 从站地址
    uint8_t func_code;      // 功能码
    uint8_t exception;      // 异常码
    uint8_t *data;         // 响应数据
    uint16_t data_len;     // 数据长度
    Modbus_Error_t error;   // 错误码
    uint32_t timestamp;    // 时间戳
} Modbus_Response_t;

// Modbus任务结果回调
typedef void (*Modbus_Callback_t)(Modbus_Response_t *response);

// Modbus任务
typedef struct {
    Modbus_Request_t request;
    Modbus_Response_t response;
    Modbus_Callback_t callback;
    uint8_t task_id;
    uint8_t priority;
    uint32_t deadline;
} Modbus_Task_t;

// Modbus主站句柄
typedef struct {
    UART_HandleTypeDef *huart;      // 串口句柄
    GPIO_TypeDef *de_port;          // DE控制端口
    uint16_t de_pin;                // DE控制引脚
    
    uint32_t baudrate;              // 波特率
    uint8_t parity;                 // 校验位
    uint8_t stopbits;               // 停止位
    
    // 缓冲区
    uint8_t tx_buffer[256];         // 发送缓冲区
    uint8_t rx_buffer[256];         // 接收缓冲区
    uint16_t rx_index;              // 接收索引
    
    // 状态
    uint8_t is_busy;                // 忙标志
    uint8_t is_initialized;         // 初始化标志
    uint32_t last_rx_time;          // 最后接收时间
    uint32_t inter_char_timeout;    // 字符间超时
    uint32_t frame_timeout;         // 帧超时
    
    // RTOS
    QueueHandle_t request_queue;    // 请求队列
    SemaphoreHandle_t mutex;        // 互斥锁
    TaskHandle_t task_handle;       // 任务句柄
    
    // 统计
    uint32_t tx_count;              // 发送计数
    uint32_t rx_count;              // 接收计数
    uint32_t error_count;           // 错误计数
    uint32_t timeout_count;         // 超时计数
} Modbus_Handle_t;

// 函数声明
// 初始化
Modbus_Error_t Modbus_Init(Modbus_Handle_t *hmodbus, UART_HandleTypeDef *huart, 
                          GPIO_TypeDef *de_port, uint16_t de_pin);
void Modbus_SetTimeout(Modbus_Handle_t *hmodbus, uint32_t inter_char_ms, uint32_t frame_ms);

// 基本功能
Modbus_Error_t Modbus_ReadCoils(Modbus_Handle_t *hmodbus, uint8_t slave_addr, 
                               uint16_t start_addr, uint16_t quantity, 
                               uint8_t *coils, uint32_t timeout_ms);
Modbus_Error_t Modbus_ReadDiscreteInputs(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                        uint16_t start_addr, uint16_t quantity,
                                        uint8_t *inputs, uint32_t timeout_ms);
Modbus_Error_t Modbus_ReadHoldingRegisters(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                          uint16_t start_addr, uint16_t quantity,
                                          uint16_t *registers, uint32_t timeout_ms);
Modbus_Error_t Modbus_ReadInputRegisters(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                        uint16_t start_addr, uint16_t quantity,
                                        uint16_t *registers, uint32_t timeout_ms);
Modbus_Error_t Modbus_WriteSingleCoil(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                     uint16_t coil_addr, uint8_t value, uint32_t timeout_ms);
Modbus_Error_t Modbus_WriteSingleRegister(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                         uint16_t reg_addr, uint16_t value, uint32_t timeout_ms);
Modbus_Error_t Modbus_WriteMultipleCoils(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                        uint16_t start_addr, uint16_t quantity,
                                        uint8_t *coils, uint32_t timeout_ms);
Modbus_Error_t Modbus_WriteMultipleRegisters(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                            uint16_t start_addr, uint16_t quantity,
                                            uint16_t *registers, uint32_t timeout_ms);

// 高级功能
Modbus_Error_t Modbus_SendRequest(Modbus_Handle_t *hmodbus, Modbus_Request_t *request,
                                 Modbus_Response_t *response);
uint8_t Modbus_AddTask(Modbus_Handle_t *hmodbus, Modbus_Task_t *task);
void Modbus_ProcessTasks(Modbus_Handle_t *hmodbus);

// 工具函数
uint16_t Modbus_CRC16(uint8_t *data, uint16_t length);
const char* Modbus_ErrorToString(Modbus_Error_t error);
const char* Modbus_ExceptionToString(uint8_t exception_code);
void Modbus_PrintFrame(uint8_t *frame, uint16_t len, const char *tag);

#endif

2、CRC16计算

// modbus_crc.c
#include "modbus_master.h"

// CRC16表(预计算)
static const uint16_t crc16_table[256] = {
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4140
};

// 计算CRC16
uint16_t Modbus_CRC16(uint8_t *data, uint16_t length)
{
    uint8_t tmp;
    uint16_t crc = 0xFFFF;
    
    while(length--) {
        tmp = *data++ ^ (uint8_t)crc;
        crc >>= 8;
        crc ^= crc16_table[tmp];
    }
    
    return crc;
}

// 添加CRC到帧
void Modbus_AddCRC(uint8_t *frame, uint16_t len)
{
    uint16_t crc = Modbus_CRC16(frame, len);
    frame[len] = crc & 0xFF;      // CRC低字节
    frame[len + 1] = crc >> 8;   // CRC高字节
}

// 验证CRC
uint8_t Modbus_CheckCRC(uint8_t *frame, uint16_t len)
{
    if(len < 2) return 0;
    
    uint16_t crc_calc = Modbus_CRC16(frame, len - 2);
    uint16_t crc_recv = (frame[len - 1] << 8) | frame[len - 2];
    
    return (crc_calc == crc_recv);
}

3、初始化函数

// modbus_master.c
#include "modbus_master.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

// 全局句柄
static Modbus_Handle_t *modbus_handles[MODBUS_PORT_6 + 1] = {NULL};

// Modbus初始化
Modbus_Error_t Modbus_Init(Modbus_Handle_t *hmodbus, UART_HandleTypeDef *huart, 
                          GPIO_TypeDef *de_port, uint16_t de_pin)
{
    if(hmodbus == NULL || huart == NULL) {
        return MODBUS_ERR_PORT;
    }
    
    // 清零句柄
    memset(hmodbus, 0, sizeof(Modbus_Handle_t));
    
    // 保存参数
    hmodbus->huart = huart;
    hmodbus->de_port = de_port;
    hmodbus->de_pin = de_pin;
    
    // 默认参数
    hmodbus->baudrate = 9600;
    hmodbus->parity = UART_PARITY_NONE;
    hmodbus->stopbits = UART_STOPBITS_1;
    hmodbus->inter_char_timeout = 5;    // 5ms字符间超时
    hmodbus->frame_timeout = 100;       // 100ms帧超时
    
    // 初始化DE引脚
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = de_pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(de_port, &GPIO_InitStruct);
    
    // 初始为接收模式
    HAL_GPIO_WritePin(de_port, de_pin, GPIO_PIN_RESET);
    
    // 创建RTOS对象
    hmodbus->request_queue = xQueueCreate(10, sizeof(Modbus_Task_t));
    hmodbus->mutex = xSemaphoreCreateMutex();
    
    if(hmodbus->request_queue == NULL || hmodbus->mutex == NULL) {
        return MODBUS_ERR_QUEUE_FULL;
    }
    
    // 注册句柄
    if(huart->Instance == USART1) {
        modbus_handles[MODBUS_PORT_1] = hmodbus;
    } else if(huart->Instance == USART2) {
        modbus_handles[MODBUS_PORT_2] = hmodbus;
    } else if(huart->Instance == USART3) {
        modbus_handles[MODBUS_PORT_3] = hmodbus;
    } else if(huart->Instance == USART6) {
        modbus_handles[MODBUS_PORT_6] = hmodbus;
    }
    
    hmodbus->is_initialized = 1;
    
    printf("Modbus主站初始化成功 (UART: 0x%08lX)\r\n", (uint32_t)huart->Instance);
    
    return MODBUS_OK;
}

// 设置超时
void Modbus_SetTimeout(Modbus_Handle_t *hmodbus, uint32_t inter_char_ms, uint32_t frame_ms)
{
    if(hmodbus == NULL) return;
    
    hmodbus->inter_char_timeout = inter_char_ms;
    hmodbus->frame_timeout = frame_ms;
}

// 发送请求帧
static Modbus_Error_t Modbus_SendFrame(Modbus_Handle_t *hmodbus, uint8_t *frame, uint16_t len)
{
    if(hmodbus == NULL || frame == NULL || len == 0) {
        return MODBUS_ERR_PORT;
    }
    
    // 等待总线空闲
    if(hmodbus->is_busy) {
        return MODBUS_ERR_BUSY;
    }
    
    // 设置忙标志
    hmodbus->is_busy = 1;
    
    // 切换为发送模式
    HAL_GPIO_WritePin(hmodbus->de_port, hmodbus->de_pin, GPIO_PIN_SET);
    HAL_Delay(1);  // 等待稳定
    
    // 发送数据
    HAL_StatusTypeDef status = HAL_UART_Transmit(hmodbus->huart, frame, len, 1000);
    
    // 切换为接收模式
    HAL_Delay(1);
    HAL_GPIO_WritePin(hmodbus->de_port, hmodbus->de_pin, GPIO_PIN_RESET);
    
    if(status != HAL_OK) {
        hmodbus->is_busy = 0;
        hmodbus->error_count++;
        return MODBUS_ERR_PORT;
    }
    
    hmodbus->tx_count++;
    hmodbus->last_rx_time = HAL_GetTick();
    
    return MODBUS_OK;
}

// 接收响应帧
static Modbus_Error_t Modbus_ReceiveFrame(Modbus_Handle_t *hmodbus, uint8_t *buffer, 
                                         uint16_t *len, uint32_t timeout_ms)
{
    if(hmodbus == NULL || buffer == NULL || len == NULL) {
        return MODBUS_ERR_PORT;
    }
    
    uint32_t start_time = HAL_GetTick();
    uint16_t index = 0;
    uint8_t byte;
    
    // 清空缓冲区
    memset(buffer, 0, 256);
    
    while(1) {
        // 检查超时
        if(HAL_GetTick() - start_time > timeout_ms) {
            hmodbus->timeout_count++;
            hmodbus->is_busy = 0;
            return MODBUS_ERR_TIMEOUT;
        }
        
        // 尝试读取一个字节
        if(HAL_UART_Receive(hmodbus->huart, &byte, 1, 10) == HAL_OK) {
            buffer[index++] = byte;
            hmodbus->last_rx_time = HAL_GetTick();
            
            // 检查是否收到完整帧
            if(index >= 5) {  // 最小帧长度
                // 检查字符间超时
                if(HAL_GetTick() - hmodbus->last_rx_time > hmodbus->inter_char_timeout) {
                    *len = index;
                    hmodbus->rx_count++;
                    hmodbus->is_busy = 0;
                    
                    // 验证帧
                    if(!Modbus_CheckCRC(buffer, index)) {
                        hmodbus->error_count++;
                        return MODBUS_ERR_CRC;
                    }
                    
                    return MODBUS_OK;
                }
            }
            
            // 防止缓冲区溢出
            if(index >= 256) {
                hmodbus->error_count++;
                hmodbus->is_busy = 0;
                return MODBUS_ERR_RESP_LEN;
            }
        }
    }
}

4、功能码实现

// 读取保持寄存器 (0x03)
Modbus_Error_t Modbus_ReadHoldingRegisters(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                          uint16_t start_addr, uint16_t quantity,
                                          uint16_t *registers, uint32_t timeout_ms)
{
    if(hmodbus == NULL || registers == NULL) {
        return MODBUS_ERR_PORT;
    }
    
    if(quantity < 1 || quantity > 125) {
        return MODBUS_ERR_ILLEGAL_DATA_VALUE;
    }
    
    // 构建请求帧
    uint8_t tx_frame[8];
    tx_frame[0] = slave_addr;
    tx_frame[1] = MODBUS_FC_READ_HOLDING_REGS;
    tx_frame[2] = (start_addr >> 8) & 0xFF;
    tx_frame[3] = start_addr & 0xFF;
    tx_frame[4] = (quantity >> 8) & 0xFF;
    tx_frame[5] = quantity & 0xFF;
    Modbus_AddCRC(tx_frame, 6);
    
    // 发送请求
    Modbus_Error_t err = Modbus_SendFrame(hmodbus, tx_frame, 8);
    if(err != MODBUS_OK) {
        return err;
    }
    
    // 接收响应
    uint8_t rx_buffer[256];
    uint16_t rx_len = 0;
    
    err = Modbus_ReceiveFrame(hmodbus, rx_buffer, &rx_len, timeout_ms);
    if(err != MODBUS_OK) {
        return err;
    }
    
    // 解析响应
    if(rx_len < 5) {
        return MODBUS_ERR_RESP_LEN;
    }
    
    // 检查异常响应
    if(rx_buffer[1] & 0x80) {  // 异常响应
        if(rx_len >= 5) {
            hmodbus->error_count++;
            return MODBUS_ERR_EXCEPTION;
        }
        return MODBUS_ERR_FUNC_CODE;
    }
    
    // 验证从站地址和功能码
    if(rx_buffer[0] != slave_addr || rx_buffer[1] != MODBUS_FC_READ_HOLDING_REGS) {
        return MODBUS_ERR_SLAVE_ADDR;
    }
    
    // 验证数据长度
    uint8_t byte_count = rx_buffer[2];
    if(byte_count != quantity * 2) {
        return MODBUS_ERR_RESP_LEN;
    }
    
    // 解析寄存器数据
    for(int i = 0; i < quantity; i++) {
        registers[i] = (rx_buffer[3 + i*2] << 8) | rx_buffer[4 + i*2];
    }
    
    return MODBUS_OK;
}

// 写入单个寄存器 (0x06)
Modbus_Error_t Modbus_WriteSingleRegister(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                         uint16_t reg_addr, uint16_t value, uint32_t timeout_ms)
{
    if(hmodbus == NULL) {
        return MODBUS_ERR_PORT;
    }
    
    // 构建请求帧
    uint8_t tx_frame[8];
    tx_frame[0] = slave_addr;
    tx_frame[1] = MODBUS_FC_WRITE_SINGLE_REG;
    tx_frame[2] = (reg_addr >> 8) & 0xFF;
    tx_frame[3] = reg_addr & 0xFF;
    tx_frame[4] = (value >> 8) & 0xFF;
    tx_frame[5] = value & 0xFF;
    Modbus_AddCRC(tx_frame, 6);
    
    // 发送请求
    Modbus_Error_t err = Modbus_SendFrame(hmodbus, tx_frame, 8);
    if(err != MODBUS_OK) {
        return err;
    }
    
    // 接收响应
    uint8_t rx_buffer[256];
    uint16_t rx_len = 0;
    
    err = Modbus_ReceiveFrame(hmodbus, rx_buffer, &rx_len, timeout_ms);
    if(err != MODBUS_OK) {
        return err;
    }
    
    // 解析响应
    if(rx_len < 8) {
        return MODBUS_ERR_RESP_LEN;
    }
    
    // 检查异常响应
    if(rx_buffer[1] & 0x80) {
        hmodbus->error_count++;
        return MODBUS_ERR_EXCEPTION;
    }
    
    // 验证响应是否与请求一致
    if(rx_buffer[0] != slave_addr || 
       rx_buffer[1] != MODBUS_FC_WRITE_SINGLE_REG ||
       rx_buffer[2] != tx_frame[2] ||
       rx_buffer[3] != tx_frame[3] ||
       rx_buffer[4] != tx_frame[4] ||
       rx_buffer[5] != tx_frame[5]) {
        return MODBUS_ERR_RESP_LEN;
    }
    
    return MODBUS_OK;
}

// 写入多个寄存器 (0x10)
Modbus_Error_t Modbus_WriteMultipleRegisters(Modbus_Handle_t *hmodbus, uint8_t slave_addr,
                                            uint16_t start_addr, uint16_t quantity,
                                            uint16_t *registers, uint32_t timeout_ms)
{
    if(hmodbus == NULL || registers == NULL) {
        return MODBUS_ERR_PORT;
    }
    
    if(quantity < 1 || quantity > 123) {
        return MODBUS_ERR_ILLEGAL_DATA_VALUE;
    }
    
    // 构建请求帧
    uint8_t tx_frame[256];
    uint16_t tx_len = 0;
    
    tx_frame[tx_len++] = slave_addr;
    tx_frame[tx_len++] = MODBUS_FC_WRITE_MULTIPLE_REGS;
    tx_frame[tx_len++] = (start_addr >> 8) & 0xFF;
    tx_frame[tx_len++] = start_addr & 0xFF;
    tx_frame[tx_len++] = (quantity >> 8) & 0xFF;
    tx_frame[tx_len++] = quantity & 0xFF;
    tx_frame[tx_len++] = quantity * 2;  // 字节数
    
    // 添加寄存器数据
    for(int i = 0; i < quantity; i++) {
        tx_frame[tx_len++] = (registers[i] >> 8) & 0xFF;
        tx_frame[tx_len++] = registers[i] & 0xFF;
    }
    
    Modbus_AddCRC(tx_frame, tx_len);
    tx_len += 2;
    
    // 发送请求
    Modbus_Error_t err = Modbus_SendFrame(hmodbus, tx_frame, tx_len);
    if(err != MODBUS_OK) {
        return err;
    }
    
    // 接收响应
    uint8_t rx_buffer[256];
    uint16_t rx_len = 0;
    
    err = Modbus_ReceiveFrame(hmodbus, rx_buffer, &rx_len, timeout_ms);
    if(err != MODBUS_OK) {
        return err;
    }
    
    // 解析响应
    if(rx_len < 8) {
        return MODBUS_ERR_RESP_LEN;
    }
    
    // 检查异常响应
    if(rx_buffer[1] & 0x80) {
        hmodbus->error_count++;
        return MODBUS_ERR_EXCEPTION;
    }
    
    // 验证响应
    if(rx_buffer[0] != slave_addr || 
       rx_buffer[1] != MODBUS_FC_WRITE_MULTIPLE_REGS ||
       rx_buffer[2] != tx_frame[2] ||
       rx_buffer[3] != tx_frame[3] ||
       rx_buffer[4] != tx_frame[4] ||
       rx_buffer[5] != tx_frame[5]) {
        return MODBUS_ERR_RESP_LEN;
    }
    
    return MODBUS_OK;
}

5、高级API(支持重试)

// 发送请求(带重试)
Modbus_Error_t Modbus_SendRequest(Modbus_Handle_t *hmodbus, Modbus_Request_t *request,
                                 Modbus_Response_t *response)
{
    if(hmodbus == NULL || request == NULL || response == NULL) {
        return MODBUS_ERR_PORT;
    }
    
    // 初始化响应
    memset(response, 0, sizeof(Modbus_Response_t));
    response->slave_addr = request->slave_addr;
    response->func_code = request->func_code;
    
    // 构建请求帧
    uint8_t tx_frame[256];
    uint16_t tx_len = 0;
    
    tx_frame[tx_len++] = request->slave_addr;
    tx_frame[tx_len++] = request->func_code;
    
    // 根据功能码构建帧
    switch(request->func_code) {
        case MODBUS_FC_READ_HOLDING_REGS:
        case MODBUS_FC_READ_INPUT_REGS:
        case MODBUS_FC_READ_COILS:
        case MODBUS_FC_READ_DISCRETE_INPUTS:
            tx_frame[tx_len++] = (request->reg_addr >> 8) & 0xFF;
            tx_frame[tx_len++] = request->reg_addr & 0xFF;
            tx_frame[tx_len++] = (request->quantity >> 8) & 0xFF;
            tx_frame[tx_len++] = request->quantity & 0xFF;
            break;
            
        case MODBUS_FC_WRITE_SINGLE_REG:
        case MODBUS_FC_WRITE_SINGLE_COIL:
            tx_frame[tx_len++] = (request->reg_addr >> 8) & 0xFF;
            tx_frame[tx_len++] = request->reg_addr & 0xFF;
            if(request->func_code == MODBUS_FC_WRITE_SINGLE_COIL) {
                tx_frame[tx_len++] = request->data[0] ? 0xFF : 0x00;
                tx_frame[tx_len++] = 0x00;
            } else {
                tx_frame[tx_len++] = (request->data[0] >> 8) & 0xFF;
                tx_frame[tx_len++] = request->data[0] & 0xFF;
            }
            break;
            
        case MODBUS_FC_WRITE_MULTIPLE_REGS:
            tx_frame[tx_len++] = (request->reg_addr >> 8) & 0xFF;
            tx_frame[tx_len++] = request->reg_addr & 0xFF;
            tx_frame[tx_len++] = (request->quantity >> 8) & 0xFF;
            tx_frame[tx_len++] = request->quantity & 0xFF;
            tx_frame[tx_len++] = request->quantity * 2;
            for(int i = 0; i < request->quantity; i++) {
                tx_frame[tx_len++] = (request->data[i] >> 8) & 0xFF;
                tx_frame[tx_len++] = request->data[i] & 0xFF;
            }
            break;
            
        default:
            return MODBUS_ERR_FUNC_CODE;
    }
    
    // 添加CRC
    Modbus_AddCRC(tx_frame, tx_len);
    tx_len += 2;
    
    // 重试机制
    uint8_t retry = 0;
    Modbus_Error_t error = MODBUS_OK;
    
    do {
        // 发送请求
        error = Modbus_SendFrame(hmodbus, tx_frame, tx_len);
        if(error != MODBUS_OK) {
            retry++;
            continue;
        }
        
        // 接收响应
        uint8_t rx_buffer[256];
        uint16_t rx_len = 0;
        
        error = Modbus_ReceiveFrame(hmodbus, rx_buffer, &rx_len, request->timeout_ms);
        if(error != MODBUS_OK) {
            retry++;
            continue;
        }
        
        // 解析响应
        if(rx_len < 5) {
            error = MODBUS_ERR_RESP_LEN;
            retry++;
            continue;
        }
        
        // 检查异常响应
        if(rx_buffer[1] & 0x80) {
            response->exception = rx_buffer[2];
            error = MODBUS_ERR_EXCEPTION;
            break;
        }
        
        // 验证从站地址
        if(rx_buffer[0] != request->slave_addr) {
            error = MODBUS_ERR_SLAVE_ADDR;
            retry++;
            continue;
        }
        
        // 解析数据
        switch(request->func_code) {
            case MODBUS_FC_READ_HOLDING_REGS:
            case MODBUS_FC_READ_INPUT_REGS:
                if(response->data != NULL) {
                    uint8_t byte_count = rx_buffer[2];
                    for(int i = 0; i < byte_count/2; i++) {
                        uint16_t val = (rx_buffer[3 + i*2] << 8) | rx_buffer[4 + i*2];
                        response->data[i] = val;
                    }
                    response->data_len = byte_count/2;
                }
                break;
                
            case MODBUS_FC_WRITE_SINGLE_REG:
            case MODBUS_FC_WRITE_SINGLE_COIL:
                // 确认写入成功
                break;
                
            case MODBUS_FC_WRITE_MULTIPLE_REGS:
                // 确认写入成功
                break;
        }
        
        break;
        
    } while(retry < request->retry_count);
    
    response->error = error;
    response->timestamp = HAL_GetTick();
    
    return error;
}

6、多从站轮询管理

// modbus_polling.c
#include "modbus_master.h"

// 从站定义
typedef struct {
    uint8_t addr;                    // 从站地址
    uint8_t enabled;                 // 是否启用
    uint32_t poll_interval;          // 轮询间隔
    uint32_t last_poll_time;         // 上次轮询时间
    
    // 寄存器映射
    struct {
        uint16_t holding[100];       // 保持寄存器
        uint16_t input[50];          // 输入寄存器
        uint8_t coils[20];           // 线圈
        uint8_t discrete[20];        // 离散输入
    } regs;
    
    // 状态
    uint8_t online;                  // 在线状态
    uint32_t last_response_time;     // 最后响应时间
    uint32_t error_count;            // 错误计数
    uint32_t timeout_count;          // 超时计数
} Modbus_Slave_t;

// 轮询管理器
typedef struct {
    Modbus_Handle_t *hmodbus;        // Modbus句柄
    Modbus_Slave_t slaves[32];       // 从站列表
    uint8_t slave_count;             // 从站数量
    
    TaskHandle_t task_handle;        // 轮询任务句柄
    uint8_t polling_enabled;         // 轮询使能
    uint32_t poll_interval;          // 默认轮询间隔
    
    // 统计
    uint32_t total_polls;            // 总轮询次数
    uint32_t success_polls;          // 成功轮询次数
    uint32_t failed_polls;           // 失败轮询次数
} Modbus_PollManager_t;

static Modbus_PollManager_t poll_manager = {0};

// 初始化轮询管理器
Modbus_Error_t Modbus_PollManager_Init(Modbus_Handle_t *hmodbus)
{
    if(hmodbus == NULL) {
        return MODBUS_ERR_PORT;
    }
    
    memset(&poll_manager, 0, sizeof(Modbus_PollManager_t));
    poll_manager.hmodbus = hmodbus;
    poll_manager.poll_interval = 1000;  // 默认1秒
    poll_manager.polling_enabled = 1;
    
    return MODBUS_OK;
}

// 添加从站
Modbus_Error_t Modbus_AddSlave(uint8_t addr, uint32_t interval_ms)
{
    if(poll_manager.slave_count >= 32) {
        return MODBUS_ERR_QUEUE_FULL;
    }
    
    Modbus_Slave_t *slave = &poll_manager.slaves[poll_manager.slave_count];
    memset(slave, 0, sizeof(Modbus_Slave_t));
    
    slave->addr = addr;
    slave->enabled = 1;
    slave->poll_interval = (interval_ms > 0) ? interval_ms : poll_manager.poll_interval;
    slave->last_poll_time = 0;
    slave->online = 0;
    
    poll_manager.slave_count++;
    
    return MODBUS_OK;
}

// 轮询单个从站
static void Poll_Slave(Modbus_Slave_t *slave)
{
    if(!slave->enabled || !poll_manager.polling_enabled) {
        return;
    }
    
    uint32_t current_time = HAL_GetTick();
    
    // 检查是否到达轮询时间
    if(current_time - slave->last_poll_time < slave->poll_interval) {
        return;
    }
    
    slave->last_poll_time = current_time;
    poll_manager.total_polls++;
    
    // 读取保持寄存器 (示例: 读取10个寄存器,地址0开始)
    uint16_t registers[10];
    Modbus_Error_t err = Modbus_ReadHoldingRegisters(poll_manager.hmodbus, 
                                                     slave->addr, 0, 10, 
                                                     registers, 1000);
    
    if(err == MODBUS_OK) {
        // 保存数据
        for(int i = 0; i < 10; i++) {
            slave->regs.holding[i] = registers[i];
        }
        
        slave->online = 1;
        slave->last_response_time = current_time;
        poll_manager.success_polls++;
        
        printf("从站 %d 轮询成功\r\n", slave->addr);
    } else {
        slave->error_count++;
        slave->online = 0;
        poll_manager.failed_polls++;
        
        printf("从站 %d 轮询失败: %s\r\n", slave->addr, 
               Modbus_ErrorToString(err));
    }
}

// 轮询任务
void Modbus_Polling_Task(void *argument)
{
    printf("Modbus轮询任务启动\r\n");
    
    while(1) {
        // 轮询所有从站
        for(int i = 0; i < poll_manager.slave_count; i++) {
            Poll_Slave(&poll_manager.slaves[i]);
            
            // 任务延时,避免同时轮询
            vTaskDelay(pdMS_TO_TICKS(10));
        }
        
        // 主循环延时
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// 启动轮询
void Modbus_StartPolling(void)
{
    xTaskCreate(Modbus_Polling_Task, "ModbusPoll", 512, NULL, 3, 
                &poll_manager.task_handle);
}

// 获取从站数据
Modbus_Error_t Modbus_GetSlaveData(uint8_t addr, uint16_t *registers, uint8_t reg_count)
{
    for(int i = 0; i < poll_manager.slave_count; i++) {
        if(poll_manager.slaves[i].addr == addr) {
            if(reg_count > 100) reg_count = 100;
            
            for(int j = 0; j < reg_count; j++) {
                registers[j] = poll_manager.slaves[i].regs.holding[j];
            }
            
            return MODBUS_OK;
        }
    }
    
    return MODBUS_ERR_SLAVE_ADDR;
}

7、任务队列管理

// modbus_queue.c
#include "modbus_master.h"

// 任务队列
#define MAX_TASKS 20
static Modbus_Task_t task_queue[MAX_TASKS];
static uint8_t task_count = 0;
static uint8_t task_id_counter = 0;

// 添加任务
uint8_t Modbus_AddTask(Modbus_Handle_t *hmodbus, Modbus_Task_t *task)
{
    if(task_count >= MAX_TASKS) {
        return 0;
    }
    
    if(hmodbus == NULL || task == NULL) {
        return 0;
    }
    
    // 获取互斥锁
    if(xSemaphoreTake(hmodbus->mutex, 100) != pdTRUE) {
        return 0;
    }
    
    // 复制任务
    memcpy(&task_queue[task_count], task, sizeof(Modbus_Task_t));
    task_queue[task_count].task_id = task_id_counter++;
    
    task_count++;
    
    // 释放互斥锁
    xSemaphoreGive(hmodbus->mutex);
    
    return task_queue[task_count-1].task_id;
}

// 处理任务
void Modbus_ProcessTasks(Modbus_Handle_t *hmodbus)
{
    if(task_count == 0 || hmodbus == NULL) {
        return;
    }
    
    // 按优先级排序(简单实现)
    for(int i = 0; i < task_count - 1; i++) {
        for(int j = i + 1; j < task_count; j++) {
            if(task_queue[j].priority > task_queue[i].priority) {
                Modbus_Task_t temp = task_queue[i];
                task_queue[i] = task_queue[j];
                task_queue[j] = temp;
            }
        }
    }
    
    // 处理任务
    for(int i = 0; i < task_count; i++) {
        Modbus_Task_t *task = &task_queue[i];
        
        // 检查截止时间
        if(task->deadline > 0 && HAL_GetTick() > task->deadline) {
            task->response.error = MODBUS_ERR_TIMEOUT;
            continue;
        }
        
        // 执行请求
        Modbus_Error_t err = Modbus_SendRequest(hmodbus, &task->request, &task->response);
        
        // 调用回调
        if(task->callback != NULL) {
            task->callback(&task->response);
        }
        
        // 从队列中移除
        for(int j = i; j < task_count - 1; j++) {
            task_queue[j] = task_queue[j + 1];
        }
        task_count--;
        i--;
        
        // 任务间延时
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

8、调试和工具函数

// modbus_utils.c
#include "modbus_master.h"
#include <stdio.h>

// 错误码转字符串
const char* Modbus_ErrorToString(Modbus_Error_t error)
{
    switch(error) {
        case MODBUS_OK: return "OK";
        case MODBUS_ERR_TIMEOUT: return "Timeout";
        case MODBUS_ERR_CRC: return "CRC Error";
        case MODBUS_ERR_EXCEPTION: return "Exception";
        case MODBUS_ERR_RESP_LEN: return "Invalid Response Length";
        case MODBUS_ERR_SLAVE_ADDR: return "Invalid Slave Address";
        case MODBUS_ERR_FUNC_CODE: return "Invalid Function Code";
        case MODBUS_ERR_QUEUE_FULL: return "Queue Full";
        case MODBUS_ERR_BUSY: return "Busy";
        case MODBUS_ERR_PORT: return "Port Error";
        default: return "Unknown Error";
    }
}

// 异常码转字符串
const char* Modbus_ExceptionToString(uint8_t exception_code)
{
    switch(exception_code) {
        case MODBUS_EXCEPTION_ILLEGAL_FUNCTION: 
            return "Illegal Function";
        case MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS: 
            return "Illegal Data Address";
        case MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE: 
            return "Illegal Data Value";
        case MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE: 
            return "Slave Device Failure";
        case MODBUS_EXCEPTION_ACKNOWLEDGE: 
            return "Acknowledge";
        case MODBUS_EXCEPTION_SLAVE_DEVICE_BUSY: 
            return "Slave Device Busy";
        case MODBUS_EXCEPTION_MEMORY_PARITY_ERROR: 
            return "Memory Parity Error";
        case MODBUS_EXCEPTION_GATEWAY_PATH_UNAVAILABLE: 
            return "Gateway Path Unavailable";
        case MODBUS_EXCEPTION_GATEWAY_TARGET_NO_RESP: 
            return "Gateway Target No Response";
        default: return "Unknown Exception";
    }
}

// 打印帧数据
void Modbus_PrintFrame(uint8_t *frame, uint16_t len, const char *tag)
{
    if(frame == NULL || len == 0) return;
    
    printf("[%s] ", tag);
    for(int i = 0; i < len; i++) {
        printf("%02X ", frame[i]);
    }
    printf("\r\n");
}

// 打印统计信息
void Modbus_PrintStatistics(Modbus_Handle_t *hmodbus)
{
    if(hmodbus == NULL) return;
    
    printf("=== Modbus Statistics ===\r\n");
    printf("Tx Count: %lu\r\n", hmodbus->tx_count);
    printf("Rx Count: %lu\r\n", hmodbus->rx_count);
    printf("Error Count: %lu\r\n", hmodbus->error_count);
    printf("Timeout Count: %lu\r\n", hmodbus->timeout_count);
    
    if(poll_manager.hmodbus == hmodbus) {
        printf("Total Polls: %lu\r\n", poll_manager.total_polls);
        printf("Success Polls: %lu\r\n", poll_manager.success_polls);
        printf("Failed Polls: %lu\r\n", poll_manager.failed_polls);
    }
    
    printf("=========================\r\n");
}

9、主程序示例

// main.c
#include "main.h"
#include "modbus_master.h"

// Modbus句柄
Modbus_Handle_t hmodbus;

// 从站数据
typedef struct {
    float temperature;
    float humidity;
    float pressure;
    uint8_t status;
} Sensor_Data_t;

static Sensor_Data_t sensor_data = {0};

int main(void)
{
    // HAL初始化
    HAL_Init();
    SystemClock_Config();
    
    // 外设初始化
    MX_GPIO_Init();
    MX_USART2_UART_Init();  // Modbus使用USART2
    MX_FreeRTOS_Init();
    
    printf("STM32F407 Modbus RTU Master\r\n");
    printf("============================\r\n");
    
    // 1. 初始化Modbus主站
    Modbus_Error_t err = Modbus_Init(&hmodbus, &huart2, GPIOA, GPIO_PIN_1);
    if(err != MODBUS_OK) {
        printf("Modbus初始化失败: %s\r\n", Modbus_ErrorToString(err));
        Error_Handler();
    }
    
    // 2. 设置超时
    Modbus_SetTimeout(&hmodbus, 5, 1000);
    
    // 3. 初始化轮询管理器
    Modbus_PollManager_Init(&hmodbus);
    
    // 4. 添加从站
    Modbus_AddSlave(1, 1000);  // 从站1,1秒轮询
    Modbus_AddSlave(2, 2000);  // 从站2,2秒轮询
    Modbus_AddSlave(3, 3000);  // 从站3,3秒轮询
    
    // 5. 启动轮询任务
    Modbus_StartPolling();
    
    // 6. 启动FreeRTOS调度器
    osKernelStart();
    
    while(1) { }
}

// 示例任务:定期读取传感器
void Sensor_Read_Task(void *argument)
{
    uint16_t registers[10];
    
    while(1) {
        // 读取从站1的保持寄存器
        Modbus_Error_t err = Modbus_ReadHoldingRegisters(&hmodbus, 1, 0, 10, 
                                                         registers, 1000);
        
        if(err == MODBUS_OK) {
            // 解析数据
            sensor_data.temperature = (float)registers[0] / 10.0f;
            sensor_data.humidity = (float)registers[1] / 10.0f;
            sensor_data.pressure = (float)((registers[2] << 16) | registers[3]) / 100.0f;
            sensor_data.status = registers[4];
            
            printf("传感器数据: %.1f°C, %.1f%%, %.1fhPa, 状态: %d\r\n",
                   sensor_data.temperature, sensor_data.humidity,
                   sensor_data.pressure, sensor_data.status);
        } else {
            printf("读取传感器失败: %s\r\n", Modbus_ErrorToString(err));
        }
        
        vTaskDelay(pdMS_TO_TICKS(5000));  // 5秒读取一次
    }
}

// 示例任务:控制执行器
void Actuator_Control_Task(void *argument)
{
    static uint8_t relay_state = 0;
    
    while(1) {
        // 切换继电器状态
        relay_state = !relay_state;
        
        // 写入单个线圈
        Modbus_Error_t err = Modbus_WriteSingleCoil(&hmodbus, 1, 0, 
                                                   relay_state, 1000);
        
        if(err == MODBUS_OK) {
            printf("继电器 %s\r\n", relay_state ? "打开" : "关闭");
        } else {
            printf("控制继电器失败: %s\r\n", Modbus_ErrorToString(err));
        }
        
        vTaskDelay(pdMS_TO_TICKS(10000));  // 10秒切换一次
    }
}

// 任务回调示例
void Task_Callback(Modbus_Response_t *response)
{
    if(response->error == MODBUS_OK) {
        printf("任务完成: 从站%d, 功能码0x%02X\r\n", 
               response->slave_addr, response->func_code);
    } else {
        printf("任务失败: %s", Modbus_ErrorToString(response->error));
        
        if(response->error == MODBUS_ERR_EXCEPTION) {
            printf(" (异常: %s)", Modbus_ExceptionToString(response->exception));
        }
        printf("\r\n");
    }
}

// 创建任务示例
void Create_Modbus_Tasks(void)
{
    // 创建读取任务
    xTaskCreate(Sensor_Read_Task, "SensorRead", 256, NULL, 2, NULL);
    
    // 创建控制任务
    xTaskCreate(Actuator_Control_Task, "ActuatorCtrl", 256, NULL, 2, NULL);
}

10、CubeMX配置

// usart.c
void MX_USART2_UART_Init(void)
{
    huart2.Instance = USART2;
    huart2.Init.BaudRate = 9600;
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
    huart2.Init.StopBits = UART_STOPBITS_1;
    huart2.Init.Parity = UART_PARITY_NONE;
    huart2.Init.Mode = UART_MODE_TX_RX;
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;
    
    HAL_UART_Init(&huart2);
}

// gpio.c
void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // DE控制引脚
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
}

参考代码 STM32F407作为Modbus主站例程 www.youwenfan.com/contentcnu/70252.html

五、测试程序

// test_modbus.c
void Test_Modbus_Master(void)
{
    printf("=== Modbus主站测试 ===\r\n");
    
    // 1. 基本通信测试
    printf("1. 基本通信测试...\r\n");
    uint16_t test_reg[10];
    Modbus_Error_t err = Modbus_ReadHoldingRegisters(&hmodbus, 1, 0, 10, 
                                                     test_reg, 1000);
    
    if(err == MODBUS_OK) {
        printf("  读取成功: ");
        for(int i = 0; i < 10; i++) {
            printf("%04X ", test_reg[i]);
        }
        printf("\r\n");
    } else {
        printf("  读取失败: %s\r\n", Modbus_ErrorToString(err));
    }
    
    // 2. 写入测试
    printf("2. 写入测试...\r\n");
    err = Modbus_WriteSingleRegister(&hmodbus, 1, 100, 0x1234, 1000);
    if(err == MODBUS_OK) {
        printf("  写入成功\r\n");
    } else {
        printf("  写入失败: %s\r\n", Modbus_ErrorToString(err));
    }
    
    // 3. 批量写入测试
    printf("3. 批量写入测试...\r\n");
    uint16_t write_data[5] = {0x1111, 0x2222, 0x3333, 0x4444, 0x5555};
    err = Modbus_WriteMultipleRegisters(&hmodbus, 1, 200, 5, write_data, 1000);
    if(err == MODBUS_OK) {
        printf("  批量写入成功\r\n");
    } else {
        printf("  批量写入失败: %s\r\n", Modbus_ErrorToString(err));
    }
    
    // 4. 任务队列测试
    printf("4. 任务队列测试...\r\n");
    Modbus_Task_t task = {0};
    task.request.slave_addr = 1;
    task.request.func_code = MODBUS_FC_READ_HOLDING_REGS;
    task.request.reg_addr = 0;
    task.request.quantity = 5;
    task.request.timeout_ms = 1000;
    task.request.retry_count = 3;
    task.callback = Task_Callback;
    task.priority = 5;
    
    uint8_t task_id = Modbus_AddTask(&hmodbus, &task);
    if(task_id) {
        printf("  任务添加成功, ID: %d\r\n", task_id);
    } else {
        printf("  任务添加失败\r\n");
    }
    
    // 处理任务
    Modbus_ProcessTasks(&hmodbus);
    
    printf("测试完成!\r\n");
}

六、常见问题解决

问题 原因 解决
无响应 DE/RE控制错误 检查控制引脚时序
CRC错误 波特率不匹配 检查主从站波特率
响应超时 从站地址错误 检查从站地址
数据错误 寄存器地址错误 检查Modbus映射表
通信不稳定 终端电阻缺失 总线两端加120Ω电阻
posted @ 2026-05-17 16:08  风一直那个吹  阅读(3)  评论(0)    收藏  举报