当前位置: 首页 > ai >正文

stm32f103rct6中使用串口1 DMA通信程序含异常处理

使用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);// 强制重置DMAHAL_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; // 启用FIFOhdma_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 TDA[错误发生] --> B{错误类型判断}B -->|UART物理层错误| C[记录错误类型]B -->|DMA传输错误| D[记录DMA错误标志]C --> E[清除UART错误标志]D --> F[清除DMA错误标志]E --> G[停止所有DMA传输]F --> GG --> 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走线远离高频信号线
http://www.xdnf.cn/news/5888.html

相关文章:

  • 数据验证库pydantic的用法
  • 力扣热题——统计平衡排列的数目
  • 进程间通信分类
  • 数组练习题
  • 采购流程规范化如何实现?日事清流程自动化助力需求、采购、财务高效协作
  • 动态查找滚动容器(通用方案)
  • 故障诊断模型评估——混淆矩阵,如何使样本量一致(上)
  • 深入浅出之STL源码分析8_三个指针
  • PostgreSQL 恢复信息函数
  • Android Exoplayer多路不同时长音视频混合播放
  • window 显示驱动开发-报告图形内存(一)
  • ElasticSeach快速上手笔记-入门篇
  • VScode 的插件本地更改后怎么生效
  • 嵌入式学习--江协51单片机day5
  • React百日学习计划——Deepseek版
  • 销量预测评估指标
  • 【工作记录】Kong Gateway 入门篇之部署及简单测试
  • mpegts.js 播放flv视频报错:PIPELINE_ERROR_DECODE: video decode error!
  • FlashInfer - 安装
  • 理解 Open vSwitch (OVS)
  • 一键转换上百文件 Word 批量转 PDF 软件批量工具
  • 大模型——Crawl4AI为 LLM 和 RAG 准备高质量网页数据
  • ‌Element UI 双击事件(@cell-dblclick 与 @row-dblclick)
  • 函数式方法的实现(JDK8+)
  • 洛谷 P3374 【模板】树状数组 1(树状数组解法)
  • C#高级编程:设计模式原则
  • 第28节:现代CNN架构-ResNet与残差连接
  • Android加固工具测评:易盾、顶象、360加固哪款更好用?
  • 【源码+文档+调试讲解】党员之家服务系统小程序1
  • 如何同步虚拟机文件夹