STM32F4 UART全数据读取方法及USART轮询接收异常求助
STM32F4 UART 读取问题:轮询方式仅拿首字符的解决办法
先帮你解决最头疼的轮询方式只能读取第一个字符的问题,再给你讲讲怎么读取UART的所有数据。
一、轮询失效的原因&修复方案
你的中断代码能正常跑,但轮询不行,主要是这几个细节没处理好:
1. 没处理UART错误标志(最关键的原因)
当UART接收数据时,如果出现溢出错误(ORE)、噪声错误(NE)或者帧错误(FE),会导致RXNE接收标志没法正常触发,后续的数据就检测不到了。中断模式下,中断触发会自动处理这些错误的影响,但轮询模式得手动清理错误标志才行。
2. 缓冲区索引的判断逻辑有问题
你代码里写的if (i > RX_BUFFERSIZE ),但数组索引是从0开始的啊!比如rxBuff长度是RX_BUFFERSIZE,最大有效索引是RX_BUFFERSIZE-1,等i等于RX_BUFFERSIZE的时候就已经越界了,得改成i >= RX_BUFFERSIZE才对。
修复后的完整轮询代码
#define RX_BUFFERSIZE 64 uint8_t rxBuff[RX_BUFFERSIZE]; uint8_t i = 0; // 一定要给i初始化0!不然会是随机值,直接乱掉 int main(void){ // 这里别忘了加USART1、GPIO的初始化代码... while(1){ // 先检查错误标志!必须先清错误,不然RXNE没法正常工作 if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) == SET || USART_GetFlagStatus(USART1, USART_FLAG_NE) == SET || USART_GetFlagStatus(USART1, USART_FLAG_FE) == SET){ // 读一下DR寄存器就能清除错误标志(顺便也清RXNE) (void)USART_ReceiveData(USART1); } // 检查有没有新的接收数据 if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET ){ rxBuff[i] = USART_ReceiveData(USART1); i++; // 修正索引判断,防止数组越界 if (i >= RX_BUFFERSIZE ){ i = 0; } } } }
额外要注意的点
- 一定要确保
i的初始值是0,要是没初始化,它会是个随机数,可能直接触发重置逻辑,把新数据覆盖掉。 - 波特率、奇偶校验、停止位这些配置要和HTERM完全匹配(既然中断模式正常,这部分应该没问题,不过可以再核对一遍)。
二、怎么读取STM32F4 UART的所有数据
读取UART所有数据的核心就是持续监测接收标志,根据你的应用场景选合适的方式:
1. 中断方式(推荐给实时性要求高的场景)
就是你已经写好的那种,用RXNE中断触发接收,每次中断读一个字节到缓冲区。还可以升级成带空闲中断的方式,一次性读完整帧数据:
- 开启USART的空闲中断(
USART_IT_IDLE) - 当空闲中断触发时,说明一帧数据发完了,这时候就能一次性处理缓冲区里的所有已接收字节
- 注意要在中断里先读USART_SR寄存器,再读DR寄存器,才能清除空闲中断标志
2. 轮询方式(适合简单场景、低波特率)
除了上面修复的基础轮询,还可以写个阻塞式读多个字符的函数,比如:
// 阻塞读取len个字符到buff里,要是需要超时可以自己加计时逻辑 void USART_ReadBlocking(USART_TypeDef* USARTx, uint8_t* buff, uint16_t len){ uint16_t count = 0; while(count < len){ // 等RXNE置位,有数据了再读 while(USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET); // 先清错误标志 if(USART_GetFlagStatus(USARTx, USART_FLAG_ORE) == SET){ (void)USART_ReceiveData(USARTx); } buff[count++] = USART_ReceiveData(USARTx); } }
3. DMA方式(最高效的批量读取)
要是需要高速接收大量数据,强烈推荐DMA+UART的组合:
- 配置DMA从USART的DR寄存器自动读数据到缓冲区
- 开启DMA的半传输或传输完成中断,当缓冲区满一半或者全满的时候触发中断处理数据
- 这种方式几乎不用CPU干预,适合高波特率、大数据量的场景
内容的提问来源于stack exchange,提问作者Omer Sahin




