You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
              }
                                    
       }
  }
}

问题根源分析

  1. 中断逻辑嵌套错误:原代码将TXE中断的处理逻辑完全嵌套在RXNE中断的判断分支内,导致只有RXNE中断触发时才会检查TXE标志,TXE中断本身触发时无法进入对应的处理流程。
  2. return语句提前退出:多个接收case分支使用return直接退出中断函数,导致接收完成后无法执行后续的TXE检查逻辑。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:29:51