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、控制引脚配置

c 复制代码
// 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、头文件定义

c 复制代码
// 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计算

c 复制代码
// 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、初始化函数

c 复制代码
// 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、功能码实现

c 复制代码
// 读取保持寄存器 (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(支持重试)

c 复制代码
// 发送请求(带重试)
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、多从站轮询管理

c 复制代码
// 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、任务队列管理

c 复制代码
// 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、调试和工具函数

c 复制代码
// 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、主程序示例

c 复制代码
// 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配置

c 复制代码
// 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/contentcsu/70252.html

五、测试程序

c 复制代码
// 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Ω电阻
相关推荐
巴巴媛6665 小时前
STM32学习笔记【38.DHT11实验】
笔记·stm32·学习
深圳市泰凌微电子5 小时前
HK航顺 HK32F407RGT7替STM32F405RGT6 微控制器32位MCU
stm32·单片机·嵌入式硬件
lzqrzpt6 小时前
LED驱动电源行业品牌格局与技术差异深度总结
python·单片机·嵌入式硬件
SteveSenna7 小时前
直流减速电机 + STM32 控制接线方案
单片机·嵌入式硬件
云栖梦泽7 小时前
Camera驱动开发与应用开发中的零拷贝与DMA
linux·驱动开发·嵌入式硬件
小心亦新10 小时前
STM32学习16--定时器输出比较2直流电机
stm32·嵌入式硬件·学习
危桥带雨11 小时前
Freertos——任务通知
stm32·单片机·嵌入式硬件·freertos
十月的皮皮12 小时前
stm20260719-STM32F103RCT6_HAL库_三人抢答器
c语言·stm32·单片机·嵌入式硬件·stm32cubemx·hal库
HPT_Lt12 小时前
告别传统二极管损耗!ZCC5050-1替代LM5050-1,冗余电源效率跃升新高度
嵌入式硬件