关于stm32f103的USART中断问题

本文介绍STM32开发过程中遇到的常见问题及解决方法:RCC配置的位置、USART中断管理策略以及使用J-Link时的调试技巧。当遇到程序跑飞或无故进入中断的情况时,尝试断电重启来解决问题。

1、时钟RCC设置 RCC_Configuration(); 一定要放在main()函数的开始处,不然会有时会出现怪异的事情

2、USART设置时,最好不要开发送中断,用到时使用USART_IT_Config开启,不然会经常进入中断

  /* Enable USART1 Receive and Transmit interrupts */

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

//  USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

3、使用J-link仿真时,如果程序经常跑飞,或者无故进入中断,接收的内容错误,最先的排除方法是停止仿真,断开电源,然后再重新仿真,反正只要是莫名其妙的问题出现,断电源重启试试。

 

上面几个问题折腾了好久。。。md


<think>我们之前已经讨论了USART发送数据的中断方式,现在用户想了解STM32F103 USART中断方式,这包括发送和接收两部分。根据引用资料,接收中断时硬件会自动清除中断标志,而发送中断有两种:TXE(发送数据寄存器空)和TC(发送完成)。下面我将系统介绍USART中断方式实现。 ### STM32F103 USART中断方式详解 #### 1. **中断类型** 在STM32F103中,USART中断事件主要包括: - **发送相关**: - `TXE`(发送数据寄存器空):当数据从发送数据寄存器(TDR)转移到移位寄存器时触发,表示可以写入新数据。 - `TC`(发送完成):整个数据帧(包括停止位)发送完成后触发。 - **接收相关**: - `RXNE`(接收数据寄存器非空):接收到数据并存入接收数据寄存器(RDR)时触发。 - `ORE`(过载错误)、`NE`(噪声错误)、`FE`(帧错误)等错误中断。 #### 2. **中断配置步骤** 以USART1为例,配置中断的通用流程如下: ##### (1) 初始化USART外设 ```c void USART1_Init(void) { // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置TX(PA9)为复用推挽输出,RX(PA10)为浮空输入 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; // TX GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; // RX GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStruct); // USART参数配置 USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 同时使能发送和接收 USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1, &USART_InitStruct); USART_Cmd(USART1, ENABLE); // 使能USART } ``` ##### (2) 配置中断优先级 ```c void USART1_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; // 子优先级 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); } ``` ##### (3) 使能中断事件 根据需求选择中断类型: ```c // 使能接收中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能发送完成中断(或USART_IT_TXE) USART_ITConfig(USART1, USART_IT_TC, ENABLE); ``` ##### (4) 编写中断服务函数 ```c void USART1_IRQHandler(void) { // 接收中断处理 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { uint8_t data = USART_ReceiveData(USART1); // 读取数据会自动清除RXNE标志 // 处理接收到的数据(例如存入缓冲区) } // 发送完成中断处理 if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) { // 当使用TC中断发送数据时,在此发送下一字节 // 注意:TC标志需要软件清除(通过读SR寄存器、写DR寄存器或向该位写0) USART_ClearITPendingBit(USART1, USART_IT_TC); // 清除TC标志 } } ``` #### 3. **关键机制说明** - **中断标志清除**: - `RXNE`:读$USART\_DR$寄存器自动清除[^1]。 - `TXE`:写$USART\_DR$寄存器或读$USART\_SR$寄存器后写$USART\_DR$寄存器清除。 - `TC`:需软件清除(读$USART\_SR$寄存器然后写$USART\_DR$寄存器,或直接向该位写0)[^2]。 - **接收不定长数据**:通常结合空闲中断(IDLE)实现,当检测到空闲线路时触发中断[^3]。 #### 4. 发送中断模式对比 | 中断类型 | 触发条件 | 适用场景 | |----------|------------------------------|------------------------| | TXE | 发送数据寄存器空 | 连续流传输(避免阻塞) | | TC | 整个数据帧(含停止位)发送完成 | 确保数据完整发送 | ### 优化技巧 1. **双缓冲区**:接收/发送均使用环形缓冲区减少中断丢失。 2. **错误处理**:在中断中加入错误状态检查: ```c if(USART_GetITStatus(USART1, USART_IT_ORE) != RESET) { // 过载错误处理 USART_ClearITPendingBit(USART1, USART_IT_ORE); } ``` 3. **DMA结合**:大量数据传输时,使用DMA+空闲中断可大幅降低CPU负载。 ### 调试建议 - 初始化顺序:时钟→GPIO→USART中断→使能USART。 - 不进中断检查: 1. NVIC配置是否正确 2. 中断使能位是否设置 3. 全局中断是否开启(`__enable_irq()`) §§相关问题§§ 1. 如何实现USART空闲中断接收不定长数据? 2. USART的TXE和TC中断在实际应用中有何区别? 3. USART中断接收数据时如何避免缓冲区溢出? 4. STM32F103多个USART同时工作时如何管理中断优先级? 5. USART通信中出现数据错误如何诊断? </think>### STM32F103 USART中断方式详解 在STM32F103中,USART中断方式通过事件触发机制实现高效数据传输,主要包括发送中断和接收中断两种工作模式。以下是核心实现要点: #### 一、中断配置流程 ```c // 1. 初始化USART外设 void USART_Config(void) { // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置PA9(TX)为复用推挽输出 GPIO_InitTypeDef GPIO_InitStruct = { .GPIO_Pin = GPIO_Pin_9, .GPIO_Mode = GPIO_Mode_AF_PP, .GPIO_Speed = GPIO_Speed_50MHz }; GPIO_Init(GPIOA, &GPIO_InitStruct); // USART参数设置 USART_InitTypeDef USART_InitStruct = { .USART_BaudRate = 115200, .USART_WordLength = USART_WordLength_8b, .USART_StopBits = USART_StopBits_1, .USART_Parity = USART_Parity_No, .USART_Mode = USART_Mode_Tx | USART_Mode_Rx, // 双工模式 .USART_HardwareFlowControl = USART_HardwareFlowControl_None }; USART_Init(USART1, &USART_InitStruct); } // 2. 配置NVIC中断控制器 void NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStruct = { .NVIC_IRQChannel = USART1_IRQn, .NVIC_IRQChannelPreemptionPriority = 0, .NVIC_IRQChannelSubPriority = 0, .NVIC_IRQChannelCmd = ENABLE }; NVIC_Init(&NVIC_InitStruct); // 使能接收中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能发送寄存器空中断 USART_ITConfig(USART1, USART_IT_TXE, ENABLE); } // 3. 中断服务函数 volatile uint8_t rxBuffer[256]; volatile uint16_t rxIndex = 0; void USART1_IRQHandler(void) { // 接收中断处理 if(USART_GetITStatus(USART1, USART_IT_RXNE)) { rxBuffer[rxIndex++] = USART_ReceiveData(USART1); // 自动清除RXNE标志[^1] if(rxIndex >= sizeof(rxBuffer)) rxIndex = 0; // 防溢出 } // 发送中断处理 if(USART_GetITStatus(USART1, USART_IT_TXE)) { if(txIndex < txLen) { USART_SendData(USART1, txBuffer[txIndex++]); } else { USART_ITConfig(USART1, USART_IT_TXE, DISABLE); // 发送完成 } // TXE标志在写DR后自动清除 } } ``` #### 二、中断类型对比 | 中断类型 | 触发条件 | 标志清除方式 | 典型应用场景 | |----------------|------------------------------|----------------------|--------------------| | **RXNE** | 接收数据寄存器非空 | 读$USART\_DR$自动清除[^1] | 实时数据接收 | | **TXE** | 发送数据寄存器空 | 写$USART\_DR$自动清除 | 流式数据传输 | | **TC** | 传输完成(含停止位) | 需软件清除 | 确保帧完整发送 | | **IDLE** | 检测到总线空闲 | 读SR+读DR清除 | 不定长数据接收 | #### 三、关键机制说明 1. **自动清除机制**: - 接收中断标志RXNE在读取$USART\_DR$寄存器后自动清除[^1] - 发送中断标志TXE在写入$USART\_DR$寄存器后自动清除 - 无需手动清除标志位,减少中断处理时间 2. **波特率配置**: $$ \text{BR} = \frac{f_{\text{PCLK}}}{16 \times \text{USARTDIV}} $$ 其中$f_{\text{PCLK}}$为外设时钟频率,USARTDIV为分频值 3. **中断优先级管理**: - 通过NVIC_SetPriorityGrouping()设置优先级分组 - 使用NVIC_SetPriority()配置具体中断优先级 - 建议接收中断优先级高于发送中断 #### 四、调试技巧 1. **中断不触发检查清单**: - 确认USART和GPIO时钟使能 - 检查NVIC配置是否正确 - 验证中断使能位(USART_ITConfig) - 测量波特率是否匹配(示波器检查波形) 2. **数据错误处理**: ```c if(USART_GetFlagStatus(USART1, USART_FLAG_ORE)) { USART_ClearFlag(USART1, USART_FLAG_ORE); // 清除过载错误 USART_ReceiveData(USART1); // 读DR清空缓冲区 } ``` #### 五、典型应用场景 1. **接收不定长数据**: ```c // 使能空闲中断 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 在中断中处理 if(USART_GetITStatus(USART1, USART_IT_IDLE)) { USART_ReceiveData(USART1); // 清除IDLE标志 processReceivedData(rxBuffer, rxIndex); // 处理数据 rxIndex = 0; // 重置索引 } ``` 2. **高效发送长数据**: ```c void StartDMA_Transmit(uint8_t* data, uint16_t len) { USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 使能DMA DMA_SetCurrDataCounter(DMA1_Channel4, len); DMA_Cmd(DMA1_Channel4, ENABLE); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值