RT-Thread论坛
直播中

余温重顾

10年用户 972经验值
擅长:可编程逻辑 嵌入式技术 EMC/EMI设计
私信 关注
[问答]

H743的LPUART1接收数据有时候出错怎么解决?

MODBUS协议,从机回复的都是正确的。LPUART1接收到就有时不正确。
波特率9600,时钟用的是内部CSI。
同一块儿板子有时出现,有时正常。有的板子出现,有的板子不出现。



回帖(1)

李泳瑜

2025-10-9 17:29:55

针对STM32H743的LPUART1接收数据偶尔出错的问题(MODBUS协议,从机回复正确,但接收时有误),结合您描述的随机性和板间差异(波特率9600,使用内部CSI时钟),以下是系统化的解决方案:




1. 时钟精度问题(首要嫌疑)


原因分析:

内部CSI时钟(RC振荡器)的初始精度和温漂可能导致波特率偏差(典型精度±4%,最大±8%)。9600波特率虽低,但累积误差在长帧传输时可能引发采样点偏移。


解决方案:  



  • 更换时钟源(强烈推荐)

    切换到HSI(16MHz,±1%)或外部晶振(HSE,±0.1%),大幅提升精度:
    // HAL库时钟配置示例(SystemClock_Config函数中):
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; // 或RCC_OSCILLATORTYPE_HSE
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    // ...(其他PLL配置)
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

  • 校准CSI(临时方案)

    若必须用CSI,通过调整RCC->ICSCR寄存器校准(参考芯片手册),但效果有限:
    RCC->ICSCR |= (0x1F << 8); // 调整CSI校准值,需实验确定最佳值




2. 波特率配置误差


检查方法:

计算实际波特率误差(要求<2%):



  • 公式

    [
    text{实际波特率} = frac{text{LPUART时钟源频率}}{text{BRR} times 16}
    ]

  • 示例

    若LPUART时钟源=64MHz(CSI),BRR值应为:
    [
    text{BRR} = frac{64000000}{9600 times 16} approx 416.67 rightarrow text{取417}
    ]
    误差=0.04%(可接受),但若CSI频率漂移至62MHz,误差达3.1% → 超限


验证步骤:

用示波器测量实际波特率波形,确认一位时长(104μs@9600)。




3. 噪声干扰与硬件优化



  • 硬件检查:  

    • 确保RS485线路使用双绞线,AB线加120Ω端电阻。

    • 检查板载电源稳定性(用示波器查看VDD纹波)。

    • 在LPUART的RX/TX线上并联30pF~100pF电容滤高频噪声。


  • 软件容错

    在接收逻辑中增加错误重发机制(MODBUS层实现):
    // 示例:检测CRC错误后请求重发
    if (!CheckModbusCRC(rx_buffer)) {
      SendModbusErrorResponse(SLAVE_ADDR, ERR_CRC);
    }




4. 驱动层优化(关键代码调整)


启用错误中断与清理标志


// LPUART初始化中启用错误中断:
__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_ERR); // 帧/噪声/溢出错误

// 中断服务函数中处理错误:
void LPUART1_IRQHandler(void) {
  if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_FE)) {
      __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_CLEAR_FEF);
      // 记录错误或重置接收状态
  }
  if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_ORE)) {
      __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_CLEAR_OREF);
      // 必须读取DR寄存器清除ORE:volatile uint32_t temp = hlpuart1.Instance->RDR;
  }
  // ...(其他中断处理)
}

使用DMA接收(推荐)


避免中断延迟导致数据丢失:


// 启用LPUART1的DMA接收
hdma_lpuart_rx.Instance = DMA1_StreamX; // 根据数据手册选择Stream
hdma_lpuart_rx.Init.Request = DMA_REQUEST_LPUART1_RX;
// ...(DMA配置)
HAL_DMA_Init(&hdma_lpuart_rx);
__HAL_LINKDMA(&hlpuart1, hdmarx, hdma_lpuart_rx);
HAL_UART_Receive_DMA(&hlpuart1, rx_buf, BUFF_SIZE);

IDLE中断检测帧结束


配合DMA实现高效帧处理:


__HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE);
// 中断中处理IDLE标志:
if (__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_IDLE)) {
  __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
  uint16_t dma_remaining = __HAL_DMA_GET_COUNTER(hdma_lpuart_rx);
  uint16_t received_len = BUFF_SIZE - dma_remaining;
  ProcessModbusFrame(rx_buf, received_len); // 处理数据
  HAL_UART_Receive_DMA(&hlpuart1, rx_buf, BUFF_SIZE); // 重启DMA
}



5. 验证与调试步骤



  1. 最小化重现

    移除MODBUS协议,直接收发固定数据(如0x55/0xAA),确认物理层问题。

  2. 监视错误标志

    在调试器中实时查看LPUART1->ISR寄存器中的FENEORE位。

  3. 功耗影响测试

    在高/低功耗模式下测试通信,排查电源波动影响。




总结排查优先级



  1. 立即行动:更换HSI/HSE时钟源 > 校准CSI > 检查波特率寄存器值。

  2. 驱动加固:启用DMA接收 + IDLE中断 + 错误标志处理。

  3. 硬件优化:检查PCB布线/电源噪声,增加滤波电容。

  4. 协议容错:MODBUS层添加重发机制。


通过以上步骤,可系统性解决由时钟漂移、硬件干扰或软件缺陷导致的随机性接收错误。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分