如何处理FreeRTOS中的超时-在vTaskDelay到期之前从中断中唤醒任务



我可以在vTaskDelay到期之前唤醒任务吗?

我有这样的代码:

在任务中(hnd_uart_task(代码:

transmit_frame();
vTaskDelay(100);  // task should wait 100 ticks or be woken up by uart ISR
parse_response();

UART中断:

// if byte was received
BaseType_t xYieldRequired = xTaskResumeFromISR(hnd_uart_task);
portYIELD_FROM_ISR(xYieldRequired);

不,因为vTaskDelay不是用来做这个的。

最接近你的解决方案是创建一个信号量,你试图在任务中延迟100毫秒,并从ISR中发出。这样,任务将阻塞最长100ms,等待信号量的给出,之后它将解除阻塞并恢复执行。如果早一点给出,它就会早一点解锁,我想这就是你想要的。

然而,根据您所写的内容,我认为您希望实现以下目标:

  • 通过UART发送一些数据
  • 等待响应
  • 一旦收到响应,就对响应采取措施

在这种情况下,在同一任务中同时执行阻塞和解析将很困难(您确实不想在ISR内部执行任何类型的解析(。因此,我推荐以下";布局";在两个任务中,一个是中断,另一个是两个任务之间共享的气味:

  1. "高级";任务(我们称之为ApplicationTask(,可以执行以下操作:
  • 构造整个帧并请求它们通过UART发送(将它们添加到某种队列中(。这个";整个框架的构造";并且将它们发送到其他任务通常会被封装到一些函数中
  • 将阻止等待响应
  • 将接收已解析的数据(包含解析数据的完整帧或对象/结构(
  1. "字节电平";任务(我们称之为ByteTask(,可以执行以下操作:
  • 具有传输数据的队列(帧队列或原始字节队列(
  • 具有接收数据的队列
  • "推";来自";要发送的数据";队列进入UART
  • 解析出现在"UART"中的UART数据;接收数据";队列并提供信号量以取消阻止ApplicationTask
  1. UART中断:
  • 仅传输ByteTask要求传输的数据
  • 将接收到的数据推入ByteTask接收队列
  1. ApplicationTask和ByteTask之间的共享信号量:
  • 每当ApplicationTask想要";"等待接收响应";,它试图接受这个信号量。最大阻塞时间可用作"阻塞时间";响应接收超时">
  • 每当ByteTask接收并解析足够的数据以决定";是的,这是一个完整的响应";,它给出了这个信号

上面是一个非常简单的例子,说明在开发应用程序时应该足够容易扩展到更多任务。你可能会有更多的想法(例如,ByteTask同时处理多个UART,有一个用于阻塞多个任务的信号量池,做一些更复杂的消息调度等(,但上面的例子应该能让你更好地了解如何处理这样的事情。

您可以使用带超时的任务通知,而不是使用vTaskDelay()

USART中断:

// if byte was received
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(hnd_uart_task, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

任务代码:

transmit_frame();
ulTaskNotifyTake(pdTRUE, 100);
parse_response();

当接收到来自ISR的任务通知时,或者当经过100 tick超时周期时,ulTaskNotifyTake(pdTRUE, 100)返回。

但正如@Jacekšlimok所指出的,逐字节解析可能不是一个好主意。确切的方法取决于所使用的协议。但通常情况下,您设置DMA或中断以用传入字节填充接收缓冲区。例如,在解析Modbus帧时,您可以使用空闲线路检测硬件中断,并向解析RX缓冲区的任务发出通知。

最新更新