引自免费微信小程序:皆我百晓生
在STM32 G431中,HAL_Delay()
函数会占用CPU时间,这可能导致串口通信的中断服务例程(ISR)被延迟执行,从而影响到串口数据的接收。为了解决这个问题,可以尝试以下几种方法:
-
使用抢占优先级更高的中断:
将串口的中断优先级设置得比延时函数执行时的任务优先级更高,这样即使有延时发生,串口的中断也会得到及时处理。首先,你需要知道当前系统使用的实时操作系统(RTOS)及中断优先级组。对于FreeRTOS,可以在任务创建时设置优先级,而对于没有RTOS的项目,可能需要在中断配置代码中调整。
-
使用非阻塞方式接收数据:
使用非阻塞方式接收数据,例如通过查询串口状态寄存器判断是否有新数据到达,再进行读取。这种方法不会阻塞其他任务的执行,但需要编写更多的管理代码。
-
使用硬件定时器:
用硬件定时器替代软件延时,这样不会阻塞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官方文档或教程。