You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

STM32F091RC UART接收函数仅返回数据包最后一字节问题求助

问题分析与修复方案:STM32 UART接收仅获取最后一字节

兄弟,你这代码明显踩了几个UART接收的典型坑,导致只能拿到最后一个字节,我给你拆解下问题,再给你修复后的代码:

核心问题点

  • 索引变量完全未更新,所有字节覆盖同一位置:你用rxd[i]存储数据,但代码里既没初始化i,也没在每次接收后递增i!相当于每次读到的字节都往同一个数组下标里塞,最后自然只剩下最后一次写入的内容。
  • 循环逻辑错配UART工作机制while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)是当有一个字节到达时才会进入循环,但你在里面套了个8次的for循环——每次读USART1->RDR后,RXNE标志会自动清零,后面7次循环读的都是无效数据,还全往同一个位置写,完全是无用操作。
  • 变量未声明:代码里的ij都没定义,编译阶段就会报错,你应该是漏写了。

修复后的轮询版本代码

先给你改个基础的轮询版本,能正确接收8字节数据包:

uint8_t rxd[10];
uint8_t rx_index = 0; // 用来跟踪当前接收的字节位置

void getChar(void) {
    // 检查是否有新字节到达
    if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
        // 只接收前8个字节,避免缓冲区溢出
        if(rx_index < 8) {
            rxd[rx_index++] = (0xFF & (USART1->RDR));
        }
        
        // 当收满8字节时,可以触发数据包处理逻辑
        if(rx_index == 8) {
            // 这里添加你的数据包处理代码,比如解析、转发到UART2等
            // process_8byte_packet(rxd);
            
            rx_index = 0; // 重置索引,准备接收下一包
        }
    }
}

更推荐的中断接收版本

轮询方式在系统有其他任务时容易丢字节,更专业的做法是用UART接收中断,确保每个字节都不会错过:

uint8_t rxd[10];
uint8_t rx_index = 0;

// USART1初始化函数(记得补充GPIO、波特率等基础配置)
void USART1_Init(void) {
    // ... 你的GPIO、波特率初始化代码 ...
    
    // 开启RXNE接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    // 使能USART1的中断通道
    NVIC_EnableIRQ(USART1_IRQn);
}

// USART1中断服务函数
void USART1_IRQHandler(void) {
    // 检查是否是RXNE中断触发
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        if(rx_index < 8) {
            rxd[rx_index++] = USART_ReceiveData(USART1);
        }
        
        if(rx_index == 8) {
            // 处理接收到的8字节数据包,比如转发到UART2
            // for(int k=0; k<8; k++) {
            //     while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
            //     USART_SendData(USART2, rxd[k]);
            // }
            
            rx_index = 0; // 重置索引,准备下一包
        }
        
        // 清除中断标志位
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

为什么这样改?

  • rx_index跟踪接收位置,每收一个字节就递增索引,确保每个字节都存在缓冲区的不同位置,不会被覆盖。
  • 每次只处理一个到达的字节,完全符合STM32 UART的RXNE标志逻辑:每收到一个字节,RXNE置位;读取RDR后,标志自动清零。
  • 中断方式能让CPU在没数据时处理其他任务,有数据时立刻响应,不会因为轮询不及时丢包,更适合实际项目使用。

内容的提问来源于stack exchange,提问作者Gaurav Sharma

火山引擎 最新活动