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);
// 强制重置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);
}
关键增强点说明:
-
错误分类检测机制
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;使用位域标志区分不同错误类型,支持多错误同时检测
-
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物理层错误类型
-
DMA错误处理增强
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { // 检查DMA传输错误标志位 // 清除所有DMA相关标志 // 完全重新初始化DMA }处理DMA传输错误和FIFO错误,并进行硬件级复位
-
状态机保护机制
volatile uint8_t is_transmitting = 0; // 发送状态标志 if(!is_transmitting) { // 仅在非发送状态处理新数据 // 启动发送前检查DMA状态 if(hdma_usart1_tx.State == HAL_DMA_STATE_READY) { is_transmitting = 1; // 启动发送 } }防止在发送过程中处理新数据导致状态混乱
-
自动恢复机制
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; // 尝试退出错误循环 } }针对可恢复错误自动重启外设,提升系统鲁棒性
-
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[保持错误状态指示]
该实现方案特点:
- 采用分层错误处理机制:物理层错误、协议层错误、DMA传输错误分开处理
- 错误状态寄存器支持多错误同时记录
- 关键操作前加入外设状态检查(如检查DMA状态是否为READY)
- 自动恢复机制最大限度减少人工干预需求
- 通过FIFO配置提升抗干扰能力
- 详细的错误指示系统(LED闪烁模式反映不同错误类型)
建议配合硬件设计加入以下保护措施:
- 在USART线路加入TVS二极管防止过压
- 使用磁珠隔离模拟地和数字地
- 确保时钟源稳定性(建议使用外部晶振)
- PCB布局时保持USART走线远离高频信号线
更多推荐

所有评论(0)