如何避免HAL_UART_RECEIVE_IT()溢出错误(错误码8)
UART接收溢出问题的解决方法
问题根源
当串口输入字节数超过设定的8字节时,在回调函数重启接收中断前,多余的字节已经进入UART的接收寄存器或FIFO,触发溢出标志(ORE),导致后续接收流程被中断,出现仅读取1字节就报错的现象。
具体解决步骤
1. 实现错误回调处理溢出
HAL库中UART溢出会触发HAL_UART_ErrorCallback,需要在此回调中清除溢出标志并丢弃残留的接收数据,之后重新启动接收:
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) { // 清除溢出错误标志 __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_ORE); // 读取并丢弃接收寄存器中残留的字节 uint8_t dummy_data; while(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE)) { dummy_data = huart2.Instance->DR; } // 重新启动8字节中断接收 HAL_UART_Receive_IT(&huart2, buffer1, 8); } }
2. 优化接收完成回调逻辑
无需手动清空buffer1,后续接收会自动覆盖原有数据,简化后的回调函数如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) { // 将8字节数据复制到buffer2 memcpy(buffer2, buffer1, 8); // 直接重启8字节中断接收 HAL_UART_Receive_IT(&huart2, buffer1, 8); } }
3. 精确处理剩余字节(可选)
如果需要实现类似“接收10字节时,先收8字节再收剩余2字节”的需求,可以维护一个接收计数变量,动态调整每次接收的字节数:
uint32_t received_bytes = 0; #define TARGET_TOTAL_BYTES 10 // 示例预期总接收字节数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) { // 计算本次实际接收的字节数(如果是剩余字节则小于8) uint32_t current_len = (received_bytes +8 > TARGET_TOTAL_BYTES) ? (TARGET_TOTAL_BYTES - received_bytes) :8; // 将数据复制到buffer2的对应位置 memcpy(&buffer2[received_bytes], buffer1, current_len); received_bytes += current_len; // 处理剩余接收或重置计数 uint32_t remaining = TARGET_TOTAL_BYTES - received_bytes; if(remaining >0) { // 接收剩余字节 HAL_UART_Receive_IT(&huart2, buffer1, remaining); } else { // 接收完成,重置计数并恢复8字节循环接收 received_bytes =0; HAL_UART_Receive_IT(&huart2, buffer1, 8); } } }
注意:此时错误回调中重启接收时,也需要根据remaining变量调整接收长度,避免再次触发溢出。
内容的提问来源于stack exchange,提问作者Patrick Daly
相关产品推荐
相关产品推荐

