STM32 USART TXE中断未触发问题求助
关于STM32 USART TXE中断未触发的问题
我在大学作业中使用STM32底层库编写带UART收发功能的代码,遇到一个问题:在USART2_IRQHandler中断处理函数中,当接收到特定数据时启用TXE中断,预期启用后会触发TXE中断并执行后续发送逻辑,但TXE中断并未触发,必须重新接收新数据触发RXNE中断才会执行发送代码。
以下是原中断处理代码:
void USART2_IRQHandler(void) { if(LL_USART_IsActiveFlag_RXNE(USART2)) { int recvd; recvd = LL_USART_ReceiveData8(USART2); if((recvd>0)&&(recvd<10)) { addr = recvd-1; LL_USART_EnableIT_TXE(USART2); } switch (recvd) { case 0: if(((mode=='s')||(mode=='l'))&&(dec_point==1)) { addr=231; LL_USART_EnableIT_TXE(USART2); } break; case 10: if((mode=='s')&&(score_addr>146)) { score_addr--; } return; case 11: if((mode=='s')&&(score_addr<151)) { score_addr++; } return; case 12: if(mode=='s') { switch (dec_point) { case 0: dec_point=1; return; case 1: dec_point=0; return; } } if(tower_height>0) { tower_height--; } LL_TIM_OC_SetCompareCH1(TIM3, 610 + tower_height*58); return; case 13: if(tower_height<10) { tower_height++; } LL_TIM_OC_SetCompareCH1(TIM3, 610 + tower_height*58); return; case 14: switch (mode) { case 't': mode='l'; step=0; return; case 'l': mode='s'; score_addr=146; dec_point=0; step=0; return; case 's': mode='t'; step=0; return; } break; case 15: mode='g'; step=0; game_tmp=0; score_addr=146; game_num_towers=4; for(int i=0; i<game_num_towers; i++) { game_towers[i]=i; game_heights[i]=i+1; } LL_USART_EnableIT_TXE(USART2); LL_USART_TransmitData8(USART2, 1); break; case 16: addr=1; LL_USART_EnableIT_TXE(USART2); LL_USART_TransmitData8(USART2, 1); break; } if(LL_USART_IsActiveFlag_TXE(USART2)) { switch (mode) { case 't': LL_USART_TransmitData8(USART2, 128+addr); LL_USART_DisableIT_TXE(USART2); break; case 'l': switch (step) { case 0: LL_USART_TransmitData8(USART2, 137+addr); LL_USART_DisableIT_TXE(USART2); step=1; break; case 1: LL_USART_TransmitData8(USART2, led_height(addr+1)); LL_USART_DisableIT_TXE(USART2); step=0; break; } break; case 's': switch (dec_point) { case 0: switch (step) { case 0: LL_USART_TransmitData8(USART2, score_addr); step=1; case 1: LL_USART_TransmitData8(USART2, led_height(addr+1)); LL_USART_DisableIT_TXE(USART2); step=0; break; } break; case 1: switch (step) { case 0: LL_USART_TransmitData8(USART2, score_addr+15); step=1; case 1: if(addr==231) { LL_USART_TransmitData8(USART2, 0); } else { LL_USART_TransmitData8(USART2, 1); } LL_USART_DisableIT_TXE(USART2); step=0; break; } break; } break; case 'g': switch (step) { case 0: if(game_tmp==game_num_towers) { step=4; game_tmp=0; return; } LL_USART_TransmitData8(USART2, game_towers[game_tmp]+128); step=1; break; case 1: LL_USART_TransmitData8(USART2, game_towers[game_tmp]+137); step=2; break; case 2: LL_USART_TransmitData8(USART2, led_height(game_heights[game_tmp])); game_tmp++; step=0; break; } break; } } } }
问题根源分析
- 中断逻辑嵌套错误:原代码将TXE中断的处理逻辑完全嵌套在RXNE中断的判断分支内,导致只有RXNE中断触发时才会检查TXE标志,TXE中断本身触发时无法进入对应的处理流程。
- return语句提前退出:多个接收case分支使用
return直接退出中断函数,导致接收完成后无法执行后续的TXE检查逻辑。 - TXE中断触发条件未匹配:TXE标志默认在发送寄存器为空时置位,但启用中断后,若当前处于RXNE中断执行过程中,NVIC不会立即触发TXE中断,需等待当前中断处理完成。
修复方案
1. 拆分中断处理逻辑
将RXNE和TXE的处理逻辑分开,各自独立判断,确保TXE中断触发时能进入对应分支:
void USART2_IRQHandler(void) { // 处理RXNE接收中断 if(LL_USART_IsActiveFlag_RXNE(USART2)) { int recvd = LL_USART_ReceiveData8(USART2); if((recvd>0)&&(recvd<10)) { addr = recvd-1; LL_USART_EnableIT_TXE(USART2); } switch (recvd) { case 0: if(((mode=='s')||(mode=='l'))&&(dec_point==1)) { addr=231; LL_USART_EnableIT_TXE(USART2); } break; case 10: if((mode=='s')&&(score_addr>146)) { score_addr--; } break; // 替换return为break,避免提前退出 case 11: if((mode=='s')&&(score_addr<151)) { score_addr++; } break; // 替换return为break case 12: if(mode=='s') { switch (dec_point) { case 0: dec_point=1; break; case 1: dec_point=0; break; } } if(tower_height>0) { tower_height--; } LL_TIM_OC_SetCompareCH1(TIM3, 610 + tower_height*58); break; // 替换return为break case 13: if(tower_height<10) { tower_height++; } LL_TIM_OC_SetCompareCH1(TIM3, 610 + tower_height*58); break; // 替换return为break case 14: switch (mode) { case 't': mode='l'; step=0; break; case 'l': mode='s'; score_addr=146; dec_point=0; step=0; break; case 's': mode='t'; step=0; break; } break; case 15: mode='g'; step=0; game_tmp=0; score_addr=146; game_num_towers=4; for(int i=0; i<game_num_towers; i++) { game_towers[i]=i; game_heights[i]=i+1; } LL_USART_EnableIT_TXE(USART2); LL_USART_TransmitData8(USART2, 1); break; case 16: addr=1; LL_USART_EnableIT_TXE(USART2); LL_USART_TransmitData8(USART2, 1); break; } } // 独立处理TXE发送中断 if(LL_USART_IsActiveFlag_TXE(USART2) && LL_USART_IsEnabledIT_TXE(USART2)) { switch (mode) { case 't': LL_USART_TransmitData8(USART2, 128+addr); LL_USART_DisableIT_TXE(USART2); break; case 'l': switch (step) { case 0: LL_USART_TransmitData8(USART2, 137+addr); LL_USART_DisableIT_TXE(USART2); step=1; break; case 1: LL_USART_TransmitData8(USART2, led_height(addr+1)); LL_USART_DisableIT_TXE(USART2); step=0; break; } break; case 's': switch (dec_point) { case 0: switch (step) { case 0: LL_USART_TransmitData8(USART2, score_addr); step=1; break; // 添加break避免分支穿透 case 1: LL_USART_TransmitData8(USART2, led_height(addr+1)); LL_USART_DisableIT_TXE(USART2); step=0; break; } break; case 1: switch (step) { case 0: LL_USART_TransmitData8(USART2, score_addr+15); step=1; break; // 添加break避免分支穿透 case 1: LL_USART_TransmitData8(USART2, addr==231 ? 0 : 1); LL_USART_DisableIT_TXE(USART2); step=0; break; } break; } break; case 'g': switch (step) { case 0: if(game_tmp==game_num_towers) { step=4; game_tmp=0; LL_USART_DisableIT_TXE(USART2); break; } LL_USART_TransmitData8(USART2, game_towers[game_tmp]+128); step=1; break; case 1: LL_USART_TransmitData8(USART2, game_towers[game_tmp]+137); step=2; break; case 2: LL_USART_TransmitData8(USART2, led_height(game_heights[game_tmp])); game_tmp++; step=0; break; case 4: LL_USART_DisableIT_TXE(USART2); break; } break; } } }
2. 关键修改点
- 将所有接收分支中的
return替换为break,确保接收完成后能继续执行TXE中断检查。 - 修复switch分支的穿透问题,在需要终止的分支添加
break。 - 独立判断TXE中断的标志位和启用状态,避免误触发。
- 在发送完成或无需继续发送时,及时禁用TXE中断,防止重复触发。
额外检查项
- 确认NVIC中已正确配置USART2的中断优先级并启用中断。
- 若需连续发送多字节,不要在发送单个字节后立即禁用TXE中断,需在所有字节发送完成后再禁用。
内容的提问来源于stack exchange,提问作者Sergeant_Keks
相关产品推荐
相关产品推荐

