使用keil5写一个关于stm32f103rct6中使用串口1通信程序,通信使用DMA收发,使用HAL库,实现一个功能为收到数据后马上回传同样的数据。

以下是针对STM32F103RCT6增强错误处理的完整DMA-UART回环通信实现,包含详细的错误分类处理和恢复机制:

#include "stm32f1xx_hal.h"
#include <string.h>

#define RX_BUFFER_SIZE  256
#define ERROR_FLASH_DELAY 100

// 定义错误类型标志位
typedef enum {
    COM_ERROR_NONE      = 0x00,
    COM_ERROR_UART_ORE  = 0x01,  // 溢出错误
    COM_ERROR_UART_NE   = 0x02,  // 噪声错误
    COM_ERROR_UART_FE   = 0x04,  // 帧错误
    COM_ERROR_UART_PE   = 0x08,  // 奇偶校验错误
    COM_ERROR_DMA_TE    = 0x10,  // DMA传输错误
    COM_ERROR_DMA_FE    = 0x20   // DMA FIFO错误
} COM_ErrorTypeDef;

volatile uint32_t com_errors = COM_ERROR_NONE;
uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint16_t received_len = 0;
volatile uint8_t is_transmitting = 0;

UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
void COM_ErrorHandler(uint32_t error_code);

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART1_UART_Init();

    // 启用UART错误中断
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_ERR);
    
    // 启动初始接收
    HAL_UART_Receive_DMA(&huart1, rx_buffer, RX_BUFFER_SIZE);
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

    while (1) {
        // 错误状态监测
        if(com_errors != COM_ERROR_NONE) {
            COM_ErrorHandler(com_errors);
            com_errors = COM_ERROR_NONE; // 清除错误寄存器
        }
        
        // 系统指示灯(正常运行时快速闪烁)
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        HAL_Delay(100);
    }
}

/* 增强型UART中断处理 */
void USART1_IRQHandler(void) {
    uint32_t isr_flags = READ_REG(huart1.Instance->SR);
    
    // 处理IDLE中断
    if((isr_flags & USART_SR_IDLE) && (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_IDLE))) {
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);
        
        if(!is_transmitting) {
            HAL_UART_DMAStop(&huart1);
            received_len = RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx);
            
            // 启动发送前检查DMA状态
            if(hdma_usart1_tx.State == HAL_DMA_STATE_READY) {
                is_transmitting = 1;
                HAL_UART_Transmit_DMA(&huart1, rx_buffer, received_len);
            }
        }
    }
    
    // 错误中断处理
    if((isr_flags & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) 
       && (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_ERR))) {
        
        // 记录具体错误类型
        if(isr_flags & USART_SR_ORE) com_errors |= COM_ERROR_UART_ORE;
        if(isr_flags & USART_SR_NE)  com_errors |= COM_ERROR_UART_NE;
        if(isr_flags & USART_SR_FE)  com_errors |= COM_ERROR_UART_FE;
        if(isr_flags & USART_SR_PE)  com_errors |= COM_ERROR_UART_PE;
        
        // 必须读取SR和DR寄存器来清除ORE标志
        volatile uint32_t temp = huart1.Instance->SR;
        temp = huart1.Instance->DR;
        (void)temp;
        
        // 立即停止DMA防止错误扩散
        HAL_UART_DMAStop(&huart1);
        huart1.RxState = HAL_UART_STATE_READY;
        huart1.TxState = HAL_UART_STATE_READY;
    }
    
    HAL_UART_IRQHandler(&huart1);
}

/* 发送完成回调 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    if(huart->Instance == USART1) {
        is_transmitting = 0;
        // 重新启动接收前检查DMA状态
        if(hdma_usart1_rx.State == HAL_DMA_STATE_READY) {
            memset(rx_buffer, 0, RX_BUFFER_SIZE);
            HAL_UART_Receive_DMA(huart, rx_buffer, RX_BUFFER_SIZE);
        }
    }
}

/* 增强型DMA错误回调 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
    if(huart->Instance == USART1) {
        // 获取详细DMA错误状态
        if(__HAL_DMA_GET_FLAG(hdma_usart1_rx.Instance, DMA_FLAG_TE1)) 
            com_errors |= COM_ERROR_DMA_TE;
        if(__HAL_DMA_GET_FLAG(hdma_usart1_rx.Instance, DMA_FLAG_FE1)) 
            com_errors |= COM_ERROR_DMA_FE;
        
        // 清除DMA错误标志
        __HAL_DMA_CLEAR_FLAG(hdma_usart1_rx.Instance, DMA_FLAG_HT1 | DMA_FLAG_TC1 | DMA_FLAG_TE1 | DMA_FLAG_FE1);
        __HAL_DMA_CLEAR_FLAG(hdma_usart1_tx.Instance, DMA_FLAG_HT1 | DMA_FLAG_TC1 | DMA_FLAG_TE1 | DMA_FLAG_FE1);
        
        // 强制重置DMA
        HAL_DMA_DeInit(&hdma_usart1_rx);
        HAL_DMA_DeInit(&hdma_usart1_tx);
        MX_DMA_Init();
    }
}

/* 错误处理函数 */
void COM_ErrorHandler(uint32_t error_code) {
    // 错误指示灯模式(不同错误不同闪烁方式)
    while(1) {
        for(uint8_t i=0; i<(error_code & 0xF); i++) {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
            HAL_Delay(ERROR_FLASH_DELAY);
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
            HAL_Delay(ERROR_FLASH_DELAY);
        }
        HAL_Delay(ERROR_FLASH_DELAY * 4);
        
        // 尝试自动恢复
        if(error_code & (COM_ERROR_UART_ORE | COM_ERROR_UART_NE | COM_ERROR_UART_FE | COM_ERROR_UART_PE)) {
            HAL_UART_DeInit(&huart1);
            MX_USART1_UART_Init();
            HAL_UART_Receive_DMA(&huart1, rx_buffer, RX_BUFFER_SIZE);
            return; // 退出错误循环
        }
    }
}

/* 其他初始化函数保持原有结构,需确保以下增强配置:*/
static void MX_DMA_Init(void) {
    // 原有配置基础上增加DMA错误中断使能
    hdma_usart1_rx.Instance = DMA1_Channel5;
    // ...
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; // 启用FIFO
    hdma_usart1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_usart1_rx.Init.MemBurst = DMA_MBURST_INC4;
    hdma_usart1_rx.Init.PeriphBurst = DMA_PBURST_INC4;
    HAL_DMA_Init(&hdma_usart1_rx);
    // 使能DMA错误中断
    __HAL_DMA_ENABLE_IT(&hdma_usart1_rx, DMA_IT_TE | DMA_IT_FE);
    
    // TX DMA类似配置
    hdma_usart1_tx.Instance = DMA1_Channel4;
    // ...
    __HAL_DMA_ENABLE_IT(&hdma_usart1_tx, DMA_IT_TE | DMA_IT_FE);
}

关键增强点说明:

  1. ‌错误分类检测机制‌

    typedef enum {
        COM_ERROR_NONE      = 0x00,
        COM_ERROR_UART_ORE  = 0x01,  // 溢出错误
        COM_ERROR_UART_NE   = 0x02,  // 噪声错误
        COM_ERROR_UART_FE   = 0x04,  // 帧错误
        COM_ERROR_UART_PE   = 0x08,  // 奇偶校验错误
        COM_ERROR_DMA_TE    = 0x10,  // DMA传输错误
        COM_ERROR_DMA_FE    = 0x20   // DMA FIFO错误
    } COM_ErrorTypeDef;
    

    使用位域标志区分不同错误类型,支持多错误同时检测

  2. ‌UART错误中断处理‌

    // 在USART1_IRQHandler中:
    if((isr_flags & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) 
       && (__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_ERR))) {
        // 详细错误记录
        // 强制清除ORE标志的特殊操作
        // 立即停止DMA
    }
    

    精确捕获所有UART物理层错误类型

  3. ‌DMA错误处理增强‌

    void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
        // 检查DMA传输错误标志位
        // 清除所有DMA相关标志
        // 完全重新初始化DMA
    }
    

    处理DMA传输错误和FIFO错误,并进行硬件级复位

  4. ‌状态机保护机制‌

    volatile uint8_t is_transmitting = 0; // 发送状态标志
    if(!is_transmitting) { // 仅在非发送状态处理新数据
        // 启动发送前检查DMA状态
        if(hdma_usart1_tx.State == HAL_DMA_STATE_READY) {
            is_transmitting = 1;
            // 启动发送
        }
    }
    

    防止在发送过程中处理新数据导致状态混乱

  5. ‌自动恢复机制‌

    void COM_ErrorHandler(uint32_t error_code) {
        // 根据错误类型尝试自动恢复
        if(error_code & UART_ERRORS_MASK) {
            HAL_UART_DeInit(&huart1);
            MX_USART1_UART_Init();
            HAL_UART_Receive_DMA(...);
            return; // 尝试退出错误循环
        }
    }
    

    针对可恢复错误自动重启外设,提升系统鲁棒性

  6. ‌DMA FIFO配置优化‌

    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_usart1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_usart1_rx.Init.MemBurst = DMA_MBURST_INC4;
    

    通过FIFO配置提升大数据量传输的稳定性

错误处理流程图

graph TD
    A[错误发生] --> B{错误类型判断}
    B -->|UART物理层错误| C[记录错误类型]
    B -->|DMA传输错误| D[记录DMA错误标志]
    C --> E[清除UART错误标志]
    D --> F[清除DMA错误标志]
    E --> G[停止所有DMA传输]
    F --> G
    G --> H[重置外设状态]
    H --> I[进入错误处理循环]
    I --> J{可恢复错误?}
    J -->|是| K[重启外设初始化]
    K --> L[恢复正常运行]
    J -->|否| M[保持错误状态指示]

该实现方案特点:

  1. 采用分层错误处理机制:物理层错误、协议层错误、DMA传输错误分开处理
  2. 错误状态寄存器支持多错误同时记录
  3. 关键操作前加入外设状态检查(如检查DMA状态是否为READY)
  4. 自动恢复机制最大限度减少人工干预需求
  5. 通过FIFO配置提升抗干扰能力
  6. 详细的错误指示系统(LED闪烁模式反映不同错误类型)

建议配合硬件设计加入以下保护措施:

  1. 在USART线路加入TVS二极管防止过压
  2. 使用磁珠隔离模拟地和数字地
  3. 确保时钟源稳定性(建议使用外部晶振)
  4. PCB布局时保持USART走线远离高频信号线
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐