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

STM32L152自定义UART协议主从心跳保活稳定性异常排查

问题原因分析

1. 状态机分支的代码逻辑错误

你提供的STATE_CONNECTED分支代码存在缩进/花括号缺失的问题:

if(WaitFullPacket() == TRUE) 
    if (ReceivePacket() == CORRECT && RX_Buffer.buffer[3] == KEEP_ALIVE)
        t_event_silence = GlobalTick;
        break;

在C语言中,无花括号的if仅作用于紧跟的第一行代码。实际执行逻辑是:

  • 若WaitFullPacket()为真,进入内层if,仅当心跳包校验正确时才更新t_event_silence
  • 无论内层if是否成立,break;都会执行,导致状态机每次进入STATE_CONNECTED分支后立即跳出,无法持续监听UART接收。这会导致心跳包的接收处理被频繁中断,t_event_silence无法及时更新,最终触发TSILENT超时断开。

2. 定时器中断的心跳发送逻辑缺陷

  • 未检查连接状态:GlobalTick == 1的分支会在系统启动后立即发送心跳包,但此时设备可能还未进入STATE_CONNECTED状态,无效数据包会干扰主从机的连接流程。
  • 未校验DMA发送状态:直接调用HAL_UART_Transmit_DMA时,若上一次DMA发送未完成,会覆盖发送缓冲区数据或导致UART硬件冲突,引发丢包或发送错误,进而触发超时断开。

3. 超时判断的时间窗口容错不足

设置TSILENT = TPOLL + 100ms时,时间窗口仅比心跳间隔多100ms,但实际系统中存在以下延迟因素:

  • UART接收的帧同步、校验耗时
  • 状态机阻塞式接收(HAL_UART_Receive的10ms超时)导致的处理延迟
  • 定时器中断的响应延迟
    这些延迟叠加后,可能导致t_event_silence的更新时机晚于TSILENT阈值,触发误断开。而扩大到TPOLL + 1000ms时,足够覆盖所有延迟,因此问题暂时消失。

解决办法

1. 修复状态机分支的逻辑错误

给if语句添加花括号,移除不必要的break,确保状态机可以持续处理STATE_CONNECTED状态下的接收操作:

case STATE_CONNECTED:   
    RX_BufferReset();
    HAL_UART_Receive(&huart3, RX_Buffer.buffer, MAX_PKT_BYTES, 10);

    if(WaitFullPacket() == TRUE) {
        if (ReceivePacket() == CORRECT) {
            // 收到任何有效数据包都更新超时标记,不止心跳包
            t_event_silence = GlobalTick;
        }
    }
    // 移除break,让状态机循环停留在该分支持续监听接收
    // break;

2. 优化定时器中断的心跳发送逻辑

  • 移除未进入连接状态时的无效心跳发送
  • 添加DMA发送状态校验,避免重复发送冲突
  • 仅在连接状态下触发心跳发送:
void TIM3_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&htim3);

  GlobalTick++;

  // 仅在连接状态下发送心跳,且检查DMA是否空闲
  if((GlobalTick - t_event_poll >= TPOLL) && (state == STATE_CONNECTED))
  {
      if(HAL_UART_GetState(&huart3) != HAL_UART_STATE_BUSY_TX) {
          TX_BufferReset();
          SendPacket(KEEP_ALIVE);
          HAL_UART_Transmit_DMA(&huart3, TX_Buffer.buffer, TX_Buffer.count);
          t_event_poll = GlobalTick;
      }
  }

  if((GlobalTick - t_event_silence >= TSILENT) && (state == STATE_CONNECTED))
  {
    state = STATE_DISCONNECTED;
    ResetTime();
  }
}

3. 优化UART接收方式(可选但推荐)

将阻塞式的HAL_UART_Receive改为DMA接收+中断回调的非阻塞方式,避免状态机被10ms超时阻塞,提升接收处理的实时性:

  • 初始化时启动DMA接收:HAL_UART_Receive_DMA(&huart3, RX_Buffer.buffer, MAX_PKT_BYTES);
  • 在HAL_UART_RxCpltCallback中处理数据包校验和t_event_silence更新

4. 合理设置超时阈值

保持TSILENT为TPOLL + 200~300ms即可覆盖系统延迟,无需扩大到1000ms。同时将超时判断从>改为>=,避免因整数溢出或计数误差导致的误判。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:10:36