RT-Thread论坛
直播中

刘刚

8年用户 1120经验值
私信 关注
[问答]

stm32h7使用uartv1和uartx都出现数据获取不正确的问题,怎么解决?


  • /**
  • * @brief   遥控器接收回调函数
  • */
  • static rt_err_t rc_rx_cbk(rt_device_t dev, rt_size_t size)
  • {
  •     rt_err_t result = rt_mq_send(&rc_rx_mq, &size, sizeof(size));

  •     return result;
  • }

  • /**
  • * @brief   遥控器接收线程
  • */
  • void rc_rx_thread_entry(void *parameter)
  • {
  •     rt_device_t rc_serial = rt_device_find("uart4");
  •     if (!rc_serial)
  •     {
  •         return ;
  •     }

  •     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;  /* 初始化配置参数 */
  •     config.baud_rate = 420000;        // 修改波特率为 9600

  •     rt_device_control(rc_serial, RT_DEVICE_CTRL_CONFIG, &config);

  •     static char msg_pool[256];
  •     /* 初始化消息队列 */
  •     rt_mq_init(&rc_rx_mq, "rc_rx_mq",
  •                msg_pool,                 /* 存放消息的缓冲区 */
  •                sizeof(rt_size_t),    /* 一条消息的最大长度 */
  •                sizeof(msg_pool),         /* 存放消息的缓冲区大小 */
  •                RT_IPC_FLAG_FIFO);        /* 如果有多个线程等待,按照先来先得到的方法分配消息 */

  •     /* 以 DMA 接收及轮询发送方式打开串口设备 */
  •     rt_device_open(rc_serial, RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_INT_TX);
  •     /* 设置接收回调函数 */
  •     rt_device_set_rx_indicate(rc_serial, rc_rx_cbk);

  •     while (1)
  •     {
  •         rt_size_t size;
  •         /* 从消息队列中读取消息 */
  •         rt_err_t result = rt_mq_recv(&rc_rx_mq, &size, sizeof(size), RT_WAITING_FOREVER);
  •         if (result == RT_EOK)
  •         {
  •             /* 从串口读取数据 */
  •             rt_size_t rx_length = rt_device_read(rc_serial, 0, rc_rx_buffer, size);
  •             // rt_kprintf("rc%dnr",rx_length);//测试用的

  •             rt_kprintf("rc:%dnr",rx_length);//输出读取到的长度
  •             for (size_t i = 0; i < rx_length; i++)
  •             {
  •                 rt_kprintf("rc:%02Xnr",rc_rx_buffer);//在终端打印接收到的十六进制值
  •             }

  •             //解析数据
  •             // crfs_decode(rc_rx_buffer,rx_length);
  •         }
  •     }

  • }



代码如上,打印在终端的hex混乱,无论是v1还是x都是如此,rx_length长度值是对的,仔细查看代码发现rc_rx_cbk实际上就在USARTx_IRQHandler中断内被调用,device_read的时候从fifobuf复制数据到我自己的buf,然后更新index,会不会是dma接收到的数据比我打印出来要快导致的?或者这段代码存在其他问题?
问题解决,感谢楼下回答,目前我的板子能正常接收串口数据了
具体检查如下:
我使用vscode开发代码,由于忘记在c_cpp_properties.json添加BSP_SCB_ENABLE_I_CACHE和BSP_SCB_ENABLE_D_CACHE两个宏导致宏开启是灰色的,导致我误以为没有开启cache
drv_common.c里面的状态:

然而我在makefile里面写了这两个宏:

然后不知道在啥时候,drv_usart.c的dma_isr和uart_isr里面的SCB_InvalidateDCache被我注释掉了,导致数据错误
解决方法:
一开始我去掉了SCB_InvalidateDCache的注释,发现代码卡在SCB_InvalidateDCache里面的while循环了,单步调试的时候发现caches的sets到达125的时候,ccsidr sets ways三个局部变量会乱跳????
吓死我了,感觉代码里面有大问题???
最终方案:注释掉SCB_EnableDCache,不用dcache了,然后drv_usart.c的两个SCB_InvalidateDCache也是注释掉,最后数据正常了

回帖(1)

贾熹

2025-10-20 17:04:55

问题分析及解决方案:STM32H7 UART 数据接收不正确


根据提供的代码和问题描述,UART 数据传输不正确可能由以下原因引起:


核心问题:接收逻辑设计缺陷



  1. 回调函数仅传递数据长度:回调函数将 size(接收到的数据长度)发送到消息队列,但 未传递实际数据

  2. 线程未读取数据:接收线程中缺少 rt_device_read() 调用,导致数据滞留在硬件缓冲区中未被读取(后续数据会覆盖旧数据)。

  3. 未处理数据连续性:UART 接收是连续的,但代码未处理数据帧边界(如协议帧头、帧尾)。




解决方案分步说明


步骤 1:修复回调函数和接收线程逻辑


// 定义数据接收缓冲区(根据实际数据长度调整)
#define RC_RX_BUF_SIZE 128
static rt_uint8_t rc_rx_buf[RC_RX_BUF_SIZE];

// 回调函数(发送实际数据 + 长度)
static rt_err_t rc_rx_cbk(rt_device_t dev, rt_size_t size) {
    if (size > RC_RX_BUF_SIZE) size = RC_RX_BUF_SIZE;
    // 立即读取数据到缓冲区
    rt_size_t read_size = rt_device_read(dev, 0, rc_rx_buf, size);

    // 发送数据和实际读取长度到消息队列
    struct {
        rt_uint8_t data[RC_RX_BUF_SIZE];
        rt_size_t size;
    } msg;

    memcpy(msg.data, rc_rx_buf, read_size);
    msg.size = read_size;
    rt_mq_send(&rc_rx_mq, &msg, sizeof(msg));

    return RT_EOK;
}

// 接收线程(完整处理数据)
void rc_rx_thread_entry(void *parameter) {
    rt_device_t rc_serial = rt_device_find("uart4");
    RT_ASSERT(rc_serial);

    // 开启中断接收模式
    rt_device_open(rc_serial, RT_DEVICE_FLAG_INT_RX);
    rt_device_set_rx_indicate(rc_serial, rc_rx_cbk);

    while (1) {
        struct {
            rt_uint8_t data[RC_RX_BUF_SIZE];
            rt_size_t size;
        } msg;

        // 等待消息队列
        if (rt_mq_recv(&rc_rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER) > 0) {
            // 处理数据(示例:打印内容)
            for (int i = 0; i < msg.size; i++) {
                rt_kprintf("%02X ", msg.data[i]);
            }
            rt_kprintf("n");
        }
    }
}

步骤 2:检查硬件配置确保正确性



  1. 确认波特率与停止位
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    config.baud_rate = BAUD_RATE;      // 如 115200
    config.data_bits = DATA_BITS_8;    // 常用 8 位数据
    config.stop_bits = STOP_BITS_1;    // 常用 1 位停止位
    config.parity    = PARITY_NONE;    // 无校验
    rt_device_control(rc_serial, RT_DEVICE_CTRL_CONFIG, &config);

  2. 检查引脚复用配置

    • 确认 UART4 的 TX/RX 引脚(如 PC10/PC11)已正确映射。

    • 参考 STM32H7 手册,配置 GPIO 为复用模式:
      __HAL_RCC_GPIOC_CLK_ENABLE();
      GPIO_InitTypeDef GPIO_Init = {0};
      GPIO_Init.Pin = GPIO_PIN_10 | GPIO_PIN_11;
      GPIO_Init.Mode = GPIO_MODE_AF_PP;
      GPIO_Init.Pull = GPIO_PULLUP;
      GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
      GPIO_Init.Alternate = GPIO_AF8_UART4; // 根据实际复用值调整
      HAL_GPIO_Init(GPIOC, &GPIO_Init);



步骤 3:启用 DMA 提升可靠性(可选)


// 开启 DMA 模式
rt_device_open(rc_serial, RT_DEVICE_FLAG_DMA_RX);

// 设置 DMA 缓冲区
rt_device_control(rc_serial, RT_DEVICE_CTRL_CONFIG, (void*)RT_DEVICE_FLAG_DMA_RX);

步骤 4:关键调试措施



  1. 逻辑分析仪检查

    • 测量 TX/RX 引脚波形,确认物理层数据传输是否正确。


  2. 添加调试输出
    // 在回调函数中添加日志
    rt_kprintf("[UART] Received %d bytesn", size);

  3. 检查时钟配置

    • 确保 UART4 时钟已使能:
      __HAL_RCC_UART4_CLK_ENABLE();





常见问题排查表
































现象 可能原因 解决方法
数据完全乱码 波特率不匹配 校准发送端/接收端波特率
数据部分丢失 缓冲区溢出或未及时读取 增大缓冲区或用 DMA 模式
仅收到第一个字节 未清除中断标志 检查 UART 中断服务程序
周期性数据错误 时钟源不稳定 切换时钟源(如 HSI→HSE)


提示:若问题依旧,请提供以下信息:  



  1. UART 初始化完整代码  

  2. 电路原理图(UART 部分)  

  3. 逻辑分析仪抓取的波形图


举报

更多回帖

×
20
完善资料,
赚取积分