我可以在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内部执行任何类型的解析(。因此,我推荐以下";布局";在两个任务中,一个是中断,另一个是两个任务之间共享的气味:
- "高级";任务(我们称之为ApplicationTask(,可以执行以下操作:
- 构造整个帧并请求它们通过UART发送(将它们添加到某种队列中(。这个";整个框架的构造";并且将它们发送到其他任务通常会被封装到一些函数中
- 将阻止等待响应
- 将接收已解析的数据(包含解析数据的完整帧或对象/结构(
- "字节电平";任务(我们称之为ByteTask(,可以执行以下操作:
- 具有传输数据的队列(帧队列或原始字节队列(
- 具有接收数据的队列
- "推";来自";要发送的数据";队列进入UART
- 解析出现在"UART"中的UART数据;接收数据";队列并提供信号量以取消阻止ApplicationTask
- UART中断:
- 仅传输ByteTask要求传输的数据
- 将接收到的数据推入ByteTask接收队列
- 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缓冲区的任务发出通知。