这篇文章的目的是介绍使用 ESP32 和 Arduino 内核的 FreeRTOS 队列。
目录
介绍
这篇文章的目的是介绍使用 ESP32 和 Arduino 内核的 FreeRTOS 队列。
队列对于任务间通信非常有用,允许在并发方面安全地将消息从一个任务发送到另一个任务 [1]。它们通常用作 FIFO(先进先出)[1],这意味着新数据插入到队列的后面并从前面使用。
尽管如此,FreeRTOS 有一个非常丰富的队列 API,它提供了更多的功能。您可以在此处查看队列 API 。
要记住的一个非常重要的方面是,插入队列中的数据是复制的,而不是仅存储对它的引用 [1]。这意味着如果我们向队列发送一个整数,它的值将被实际复制,如果我们在此之后更改原始值应该不会出现问题。
尽管如此,我们仍然可以插入指向数据的指针作为队列的元素,这在要交换的消息很大时特别有用。在这种情况下,指针将被复制到队列中,而不是消息本身,因此我们需要保证它不会被更改。但这是一个更高级的情况,我们不打算在这里介绍。
要记住的其他重要行为是,插入满队列或消耗空队列可以在指定的时间 [1] 内阻塞调用(此时间量是 API 的参数)。
尽管如前所述,队列通常用于任务间通信,但对于这个介绍性示例,我们将在 Arduino 主循环函数的队列中插入和使用元素,以便专注于我们需要执行的基本 API 调用。
编写程序
对于本教程,我们不需要任何额外的库。因此,我们将通过声明QueueHandle_t类型的全局变量开始我们的代码,这是我们需要引用 FreeRTOS 队列的类型。
QueueHandle_t queue;
转到设置功能,我们将首先打开一个串行连接,我们将使用它来输出程序的结果。
接下来,我们将通过调用 xQueueCreate函数来创建队列。该函数接收队列在给定时间可以容纳的最大元素数作为第一个输入,第二个参数接收每个元素的大小(以字节为单位)[2]。请注意,队列的每个元素都应具有相同的大小 [2]。
因此,我们将创建一个最多可容纳 10 个元素的队列,并且由于它将包含整数,因此我们可以通过调用sizeof函数来获取整数的大小(以字节为单位)。
成功执行后,xQueueCreate函数将返回队列的句柄,其类型为 QueueHandle_t [2],与我们全局声明的变量相同。如果队列分配出现问题,它将返回 NULL [2]。因此,我们还将对 setup 函数进行 NULL 检查,并在出现问题时警告用户。
void setup() {
Serial.begin(115200);
queue = xQueueCreate( 10, sizeof( int ) );
if(queue == NULL){
Serial.println("Error creating the queue");
}
}
继续主函数,我们现在将首先在队列中插入值以供以后使用。要在队列中插入一个项目,我们只需调用 xQueueSend 函数,它会在队列末尾插入一个元素 [3]。
该函数接收队列句柄 [3] 作为第一个输入,它将是我们声明的全局变量,并分配给队列创建函数的调用结果。作为第二个输入,它接收一个指向我们要插入的项目的指针(请记住,虽然我们传递了一个指针,但该项目实际上会被复制)和作为最后一个参数,任务应该阻塞等待的最长时间,以防万一队列已满 [3]。
对于最后一个参数,值在 ticks [3] 中指定,我们将传递值 portMAX_DELAY,这意味着如果队列已满,我们将无限期等待。尽管如此,考虑到我们构建程序的方式,当队列已满时我们永远不会尝试插入,因此主循环永远不会阻塞。
由于我们的队列最多可以容纳 10 个元素,因此我们将执行一个简单的 for 循环,并在每次迭代时插入当前值。
for(int i = 0; i<10; i++){
xQueueSend(queue, &i, portMAX_DELAY);
}
请注意,我们总是传递一个指向同一个变量的指针,但由于它的实际值将被复制,因此在每次迭代中将其更改为新值没有问题,因为我们将在运行代码时确认。
我们将遵循相同的循环方法来消费队列中的项目。所以,要消费一个项目,我们只需要调用xQueueReceive函数。它将接收作为第一个输入队列的句柄,作为第二个输入一个指向缓冲区的指针,该缓冲区将接收到的项目将被复制到该缓冲区,最后是在队列为空时等待的滴答数。
和以前一样,我们将全局队列句柄变量作为第一个参数传递,并将portMAX_DELAY值作为最后一个参数传递。至于项目被复制到的缓冲区,我们需要在消费项目之前声明一个整数类型的变量,我们将使用它来存储接收到的项目。
请注意,在消费该项目后,它将从队列中删除。如果您不想在检索时删除项目,可以使用xQueuePeek函数。
在我们消耗元素的循环中,我们还将它们打印到串行端口,如下所示。
int element;
for(int i = 0; i<10; i++){
xQueueReceive(queue, &element, portMAX_DELAY);
Serial.print(element);
Serial.print("|");
}
完整的源代码可以在下面看到。我们还在 Arduino 主循环开始时进行空值检查,以避免在队列尚未分配时对其进行操作。我们还在主循环的每次迭代之间添加了延迟:
测试代码
要测试代码,只需编译并使用 Arduino IDE 上传即可。然后,打开串行监视器,波特率设置为初始化函数 ( 115200 ) 中指定的波特率。您应该得到类似于图 1 的输出,它显示了在主循环函数的每次迭代中打印的队列插入项。
2K屏幕,浏览器150%缩放,右边导航栏碍事
缩放太大了
强烈支持
谢谢贴主,学习一下
感谢分享
学习一下