中断模式下软UART数据损坏,仅读取条形码首字符求助
1. 接收完成判断逻辑过早终止定时器
你在定时器中断回调里,一检测到SUart[0].RxTimingFlag == 0且SUart[0].RxBitCounter == 0就立刻停定时器、关软UART接收。但条码扫描器输出的是连续字符流(完整条码数据+回车),第一个字符接收完后,下一个字符的起始位(下降沿)会紧接着到来,此时定时器已经停了、软UART也禁用了,后续字符自然抓不到。
修复方案:
删掉定时器回调里直接停定时器的逻辑,改成只有收到条码结束符(比如\r)时再停止定时器、处理数据。示例:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &htim3) { SoftUartHandler(); // 仅当接收到回车符时,才停止定时器并处理数据 uint8_t temp = SUart[0].RxBuf; // 假设库中RxBuf存当前接收的字符 if (temp == '\r') { HAL_TIM_Base_Stop_IT(htim); SoftUartDisableRx(0); printData(); } } }
2. printData()仅读取单个字符
你的printData()每次只调用getChar(0)一次,但软UART缓冲区里可能已经存了整个条码的多个字符,这就导致只输出第一个,剩下的字符留在缓冲区里,下次触发时可能被覆盖或无法读取。
修复方案:
循环读取缓冲区里的所有字符,直到空为止:
void printData(void) { uint8_t ch; uint8_t buffer[100]; uint8_t bufferIndex = 0; // 循环读取所有已接收的字符 while (SoftUartRxAvailable(0)) { // 假设库有判断缓冲区是否有数据的函数 ch = getChar(0); HAL_UART_Transmit(&huart2, &ch, 1, HAL_MAX_DELAY); if (ch == '\r') { buffer[bufferIndex++] = '\r'; buffer[bufferIndex++] = '\n'; HAL_UART_Transmit(&huart2, buffer, bufferIndex, HAL_MAX_DELAY); bufferIndex = 0; } else { buffer[bufferIndex++] = ch; if (bufferIndex >= sizeof(buffer)) { HAL_UART_Transmit(&huart2, buffer, bufferIndex, HAL_MAX_DELAY); bufferIndex = 0; } } } }
如果库没有SoftUartRxAvailable(),可以查SUart结构体里的字段(比如RxCount)判断缓冲区剩余字符数。
3. EXTI与定时器中断优先级冲突
如果EXTI(PIN13对应的中断线)优先级比Timer3低,后续字符的起始位下降沿可能无法及时触发EXTI,导致软UART没法启动接收后续字符。
修复方案:
在CubeMX里调中断优先级,让EXTI15_10_IRQn(对应PIN13)的抢占优先级高于TIM3_IRQn。比如EXTI设为2,Timer3设为3。
4. 软UART接收状态未正确重置
第一个字符接收完后,软UART的内部状态(比如RxTimingFlag、RxBitCounter)可能没重置,导致后续字符无法被正确捕获。
修复方案:
在调用SoftUartEnableRx(0)前手动重置状态(确认库逻辑允许的前提下):
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_13) { // 重置接收状态 SUart[0].RxTimingFlag = 0; SUart[0].RxBitCounter = 0; SUart[0].RxByte = 0; // 启用接收并启动定时器 SoftUartEnableRx(0); HAL_TIM_Base_Start_IT(&htim3); } }
内容的提问来源于stack exchange,提问作者Marek

