Hans_Rudle 2024-05-20 21:08 采纳率: 77.8%
浏览 18
已结题

STM32G431串口与hal_delay连用的问题

今天写代码的时候用了串口和hal_delay,但在接收数据的时候发现stm32接收不到数据,但如果把hal_delay去掉的话便能正常运行,stm32接收的时候用的是阻塞式接收,这是问题出现位置的代码,串口接收跳出时间为1s,发送端是每 500ms发送一次数据

void crawl_goods()
{
    Servo_Setangle1(angle1);
    Servo_Setangle4(angle4);
    HAL_Delay(1000);
    Servo_Setangle3(angle3);
    HAL_Delay(1000);
    Servo_Setangle2(angle2);
}

接收串口数据时用的是阻塞式接收

HAL_UART_Receive(&huart3,BUFF1,10,1000);
  • 写回答

4条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-05-20 21:08
    关注

    引自免费微信小程序:皆我百晓生

    在STM32 G431中,HAL_Delay() 函数会占用CPU时间,这可能导致串口通信的中断服务例程(ISR)被延迟执行,从而影响到串口数据的接收。为了解决这个问题,可以尝试以下几种方法:

    1. 使用抢占优先级更高的中断: 将串口的中断优先级设置得比延时函数执行时的任务优先级更高,这样即使有延时发生,串口的中断也会得到及时处理。首先,你需要知道当前系统使用的实时操作系统(RTOS)及中断优先级组。对于FreeRTOS,可以在任务创建时设置优先级,而对于没有RTOS的项目,可能需要在中断配置代码中调整。

    2. 使用非阻塞方式接收数据: 使用非阻塞方式接收数据,例如通过查询串口状态寄存器判断是否有新数据到达,再进行读取。这种方法不会阻塞其他任务的执行,但需要编写更多的管理代码。

    3. 使用硬件定时器: 用硬件定时器替代软件延时,这样不会阻塞CPU,同时也能保证精确的时间间隔。硬件定时器的中断不会受到软件延时的影响。

    下面是针对第2点的示例代码,采用查询方式接收数据:

    #define UART_TIMEOUT_MS 1000
    
    // 查询接收缓冲区是否已满
    uint8_t UART_IsRxBufferFull(UART_HandleTypeDef *huart)
    {
        return (huart->Instance->SR & UART_SR_RXNE) ? 1 : 0;
    }
    
    // 非阻塞方式接收数据
    int ReceiveDataBlockingless(UART_HandleTypeDef *huart, uint8_t *BUFF, int size, uint32_t timeout_ms)
    {
        uint32_t start_time = HAL_GetTick();
        int received_count = 0;
    
        while(received_count < size && HAL_TimeOut == HAL_WaitForEventTimeout(&huart->RxRing, UART_TIMEOUT_OCCURRED, timeout_ms))
        {
            if(UART_IsRxBufferFull(huart))
            {
                BUFF[received_count++] = huar->Instance->DR; // 从DR寄存器读取数据
            }
        }
    
        return received_count;
    }
    
    void crawl_goods()
    {
        Servo_Setangle1(angle1);
        Servo_Setangle4(angle4);
    
        // 使用硬件定时器替换HAL_Delay(1000); 这里省略硬件定时器的初始化和配置代码
        StartHardwareTimer();
    
        while (!IsHardwareTimerExpired())
        {
            // Do nothing, wait for hardware timer to expire
        }
    
        StopHardwareTimer();
    
        Servo_Setangle3(angle3);
    
        // 同样使用硬件定时器替换HAL_Delay(1000); 这里省略硬件定时器的初始化和配置代码
        StartHardwareTimer();
    
        while (!IsHardwareTimerExpired())
        {
            // Do nothing, wait for hardware timer to expire
        }
    
        StopHardwareTimer();
    
        Servo_Setangle2(angle2);
    }
    
    // 在主循环或其他合适的地方调用
    uint8_t BUFF1[10];
    int data_received = ReceiveDataBlockingless(&huart3, BUFF1, 10, UART_TIMEOUT_MS);
    if(data_received > 0)
    {
        // 处理接收到的数据
    }
    

    对于第3点,关于硬件定时器的实现取决于你使用的具体STM32系列和开发环境。你需要查找相关文档并配置一个硬件定时器来产生指定时间的中断,然后在定时器中断服务程序中调用 HAL_Delay() 或者执行其他动作。这个过程比较复杂,通常涉及到定时器库函数的使用,以及定时器配置的硬编码,这里不再详述。如果你对硬件定时器不熟悉,建议先学习相关的STM32官方文档或教程。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 5月31日
  • 已采纳回答 5月23日
  • 修改了问题 5月20日
  • 修改了问题 5月20日
  • 展开全部

悬赏问题

  • ¥15 三极管电路求解,已知电阻电压和三级关放大倍数
  • ¥15 ADS时域 连续相位观察方法
  • ¥15 Opencv配置出错
  • ¥15 模电中二极管,三极管和电容的应用
  • ¥15 关于模型导入UNITY的.FBX: Check external application preferences.警告。
  • ¥15 气象网格数据与卫星轨道数据如何匹配
  • ¥100 java ee ssm项目 悬赏,感兴趣直接联系我
  • ¥15 微软账户问题不小心注销了好像
  • ¥15 x264库中预测模式字IPM、运动向量差MVD、量化后的DCT系数的位置
  • ¥15 curl 命令调用正常,程序调用报 java.net.ConnectException: connection refused