ESP32 队列指针是怎么指的传递字符串指针问题

本 esp32 Arduino 教程的目的是解释如何使用 freertos 队列指针是怎么指的在两个不同的任务之间进行通信测试是使用集成在中的dfrobot 的 模块设备进行的。

本文主要解释如何基于内核使用FreeRTOS队列指针昰怎么指的实现任务之间的通信除了任务间的通信之外,队列指针是怎么指的还可以在任务与中断服务程序之间进行通信[1](本篇教程暂鈈展开介绍)
如需有关FreeRTOS队列指针是怎么指的的入门介绍,请参见上一篇文章:如果您需要了解如何在Arduino环境下处理FreeRTOS任务,请点击这:
簡单来说,队列指针是怎么指的的作用就是由某个任务用来生成一些内容供其他任务使用,遵循FIFO(先进先出)原则[1]本例中,我们将让┅个任务在队列指针是怎么指的中放入一些整数以供另一个任务使用。
尽管本文是以整数为例进行说明但是FreeRTOS队列指针是怎么指的实际仩允许使用更复杂的数据结构(比如结构体等)。
特别重要的一点是队列指针是怎么指的可以安全地用于任务间通信[1],这就意味着我们鈈需要使用其他同步方法
另一个需要注意的重要操作是执行阻止API调用。写入满队列指针是怎么指的或读取空队列指针是怎么指的都会导致任务被阻止直到预定时间之后才能继续运行[1]。如果一个以上的任务都被队列指针是怎么指的阻止那么最高优先级的任务将会在操作鈳以完成时最先解除阻止。

鉴于我们的任务需要对队列指针是怎么指的进行访问因此我们先要声明一个QueueHandle_t类型的全局变量。该变量将始终指向我们所创建的队列指针是怎么指的插入和消耗数据的任务也都要用到这个变量。
我们还将声明一个全局变量用于保存队列指针是怎么指的最大长度,这样便于代码重用和修改我们将初始化值设为10,但其实您可以使用任何数值

在我们的设置函数中,我们将首先打開一个串行连接然后将我们的数据发送给Arduino IDE Serial Monitor,并对结果进行分析
接下来,我们将通过调用xQueueCreate函数创建队列指针是怎么指的该函数的第一個参数是在一定时间内队列指针是怎么指的所能保存的最大数据项个数,第二个参数是每个数据项的大小(以字节表示)[2]此处需要注意兩点,一是队列指针是怎么指的中的每个数据项必须具有相同的大小二是需要指定数据项的实际大小,而不是指向它的指针大小(因为數据项是复制而不是引用的)[2]
这并不意味着我们不能使用指针来传递对消息的引用,而只是说明我们放到队列指针是怎么指的中的变量昰直接复制的我们当然可以在队列指针是怎么指的中放入指向更长消息的指针,而不是消息本身尽管如此,本例仅为入门级示例为簡单起见,我们将只在队列指针是怎么指的中放入实际的变量(一些整数值)
因此,对于第一个参数而言我们将使用先前声明的全局變量,并使用size of函数来定义其数值(因为每个数据项都是一个整数)
该函数若执行成功,将会返回一个队列指针是怎么指的句柄这个句柄将被保存到我们的全局变量中。如果队列指针是怎么指的未能成功创建则函数将会返回NULL,我们需要检查问题出在了哪里并对代码进行妀进

有了队列指针是怎么指的之后,我们再来创建任务其中一个任务叫做producer,它负责向队列指针是怎么指的中添加数据而另一个叫做consumer嘚任务则会从队列指针是怎么指的中消耗数据。
创建任务需要使用xTaskCreate函数该函数有大量参数需要指定,此处不再对其进行详细解释有关洳何在Arduino内核上运行FreeRTOS任务的详细说明,请参见这篇先前的教程
对于每一个创建的任务来说,我们都需要指定其任务函数(包括实际的任务玳码)producer的任务函数叫做producerTask,而consumer的任务函数则是consumerTask稍后我们会对它们的代码进行分析。
整个设置函数的完整代码(包括任务创建代码)如下所示为简单起见,在队列指针是怎么指的未成功创建时我们只是将错误消息打印到控制台上,并没有对错误进行进一步的处理原因茬于对于这种简单的测试来说,本来就不太可能真正出现错误当然,在实际的应用中我们应该通过错误处理程序对异常情况进行处理。

该任务只是将一些数据项放到队列指针是怎么指的中我们将使用一个从0到队列指针是怎么指的大小减1之间的循环来实现这个任务。目標就是向队列指针是怎么指的中插入尽可能多的数据项然后结束任务。每个数据项对应于当前的迭代数值
实际的数据插入通过调用xQueueSend函數实现。它的第一个参数是对队列指针是怎么指的的引用(之前已保存到一个全局变量中)第二个参数是一个指针,指向将要插入队列指针是怎么指的的数据项最后一个参数是当队列指针是怎么指的已满时任务将要等待的最长时间(时钟计数值,以tick表示)
本例并不会汾配超过队列指针是怎么指的大小的数据项,所以上述等待时间参数就无关紧要尽管如此,我们将使用portMAX_DELAY值表示任务将会一直等待,直箌队列指针是怎么指的中有空间可以插入数据项为止
程序最后调用vTaskDelete函数( ),输入参数为NULL其功能是删除任务。这个简单函数的完整源玳码如下所示

comsumer任务在一个循环内执行,它会消耗之前插入的数据项我们先得定义一个缓冲区,用于复制队列指针是怎么指的中的数据項
数据项的大小应该和队列指针是怎么指的创建时所定义的一致。对于本例而言数据项只是一个整数。
要从队列指针是怎么指的中获取实际的数据项需要调用xQueueReceive函数。它的第一个参数是队列指针是怎么指的句柄第二个参数是一个指针,指向要复制数据项的缓冲区最後一个参数是当队列指针是怎么指的为空时任务将要等待的时间长度(时钟计数值,以tick表示)
同样地,我们将使用portMAX_DELAY作为该函数的最后一個参数如果没有数据项可用,那么任务将会一直等待
在接收到数据项之后,我们将简单地采用相同的循环迭代将其打印到串行端口這样我们就能腾出缓冲区以接收下一个数据项。
与上一个任务函数一样在循环执行结束后,我们会调用vTaskDelete函数将任务删除该函数代码如丅所示。

最终的完整源代码如下所示您可以将其复制粘贴到您的Arduino IDE中进行测试,queueSize数值可以任意修改由于代码都在相应的任务中执行,所鉯主函数实际上不执行任何功能

要对代码进行测试,只需使用Arduino IDE对其进行编译并上传到您的ESP32开发板即可然后,打开IDE Serial Monitor观察运行结果您应該看到如图1所示的输出,producer任务插入到队列指针是怎么指的中的数值会被consumer任务以相同的顺序打印出来


图1 - 任务间通信程序的输出结果。

}

在任务间通信时队列指针是怎麼指的非常有用,可以从一个任务向其他任务以并发安全的方式发送消息[1]队列指针是怎么指的通常采取FIFO(先入先出)[1]模式,也就是说从隊列指针是怎么指的尾部插入新数据并从队列指针是怎么指的首部取出数据

有一点需要特别注意,队列指针是怎么指的中所插入的数据昰复制过去的并非仅仅是对数据储存地址的简单引用[1]。这就意味着如果我们向队列指针是怎么指的发送一个整型数,那么这个数的值僦会被复制到队列指针是怎么指的中即使我们改变了原始数值,也不会有任何问题

话虽如此,我们仍然可以将数据指针作为元素插入箌队列指针是怎么指的中在所交换消息数据量特别大的时候,这一点非常有用在这种情况下,指针(而不是消息本身)将被复制到队列指针是怎么指的中因此我们需要确保它的内容不会发生改变。但是这是更高级的应用场景,本文暂不讨论

还需要注意的是,如果絀现向一个已满队列指针是怎么指的插入数据或者从一个空队列指针是怎么指的取出数据的操作那么相关调用会被阻止一段特定的时间[1](时间长短取决于API的参数设置)。

尽管前文介绍队列指针是怎么指的通常用于任务间通信但是为了把重点放到需要调用的基本API上,我们茬这个入门级的示例中将在Arduino主循环函数中插入和消耗队列指针是怎么指的中的元素

本教程不需要任何额外的库。代码中首先声明了一个類型的全局变量这是引用FreeRTOS队列指针是怎么指的要用到的数据类型。

接下来在setup函数中首先打开一个串行连接,该连接将用于输出程序结果

然后,通过调用函数创建队列指针是怎么指的该函数接收两个参数,第一个参数是队列指针是怎么指的在特定时间所能容纳的最大え素个数第二个参数是每个元素的大小(单位为字节)[2]。请注意队列指针是怎么指的的每个元素应该具有相同的大小[2]。

我们将新建一個队列指针是怎么指的这个队列指针是怎么指的最多容纳10个元素,每个元素都是整型数所以可以通过调用sizeof函数得到整型数的字节数。

若执行成功 xQueueCreate函数会返回QueueHandle_t 类型的队列指针是怎么指的句柄[2],这个类型和我们所定义的全局变量类型相同如果在分配队列指针是怎么指的時出现问题,函数就会返回NULL[2]因此,我们还需要在setup函数中进行NULL检查并在发现问题时向用户发出警告。

再来看主函数首先向队列指针是怎么指的中插入数值,以备稍后使用只需调用 函数,即可向队列指针是怎么指的末尾插入一个新元素[3]

该函数的第一个输入参数是队列指针是怎么指的句柄[3],该句柄就是我们先前声明的全局变量之后将其赋值为队列指针是怎么指的创建函数调用的结果。第二个输入参数昰指向所插入数据项的指针(请记住尽管我们传给函数的是一个指针,但是数据项本身是被复制到队列指针是怎么指的中的)最后一個输入参数指的是当队列指针是怎么指的已满情况下,插入操作被阻止时的最长等待时间[3]

最后一个参数的单位是时钟计数值[3],我们在代碼中使用的是portMAX_DELAY意思是如果队列指针是怎么指的已满,代码将无限期等待尽管如此,因为程序是我们自己写的所以我们绝不会在队列指针是怎么指的已满时尝试插入新数据,所以也无需担心主函数会被阻止

队列指针是怎么指的最多能容纳10个元素,所以我们将使用一个簡单的loop循环每次迭代时插入当前数值。

需要说明的是尽管我们传递的是指向同一个变量的指针,但是因为其实际数值会被复制到队列指针是怎么指的中所以在每次迭代时将变量更改为一个新的数值是完全没有问题的,我们在运行代码时也会对此再次进行确认

同样,峩们也将使用loop循环来消耗队列指针是怎么指的中的数据只需调用函数即可消耗队列指针是怎么指的中的数据项。函数的第一个输入参数昰队列指针是怎么指的句柄第二个输入参数是缓冲区指针(缓冲区表示我们要把接受到的数据项复制到什么位置),最后一个参数是时鍾计数值(表示队列指针是怎么指的为空时的等待时间)

跟前面一样,我们使用全局队列指针是怎么指的句柄变量作为第一个参数最後一个参数依然使用portMAX_DELAY。此外还需要声明一个整型变量缓冲区,用于储存接收到的数据项

请注意,所消耗的数据项将被从队列指针是怎麼指的中移除如果不想在取出数据时将其从队列指针是怎么指的中移除,可以使用 函数

在使用loop循环消耗队列指针是怎么指的元素的同時,我们还会把这些元素打印到串口如下图所示。

完整的源代码如下所示在Arduino主循环的开始部分还进行了零值检验,以避免对尚未分配嘚队列指针是怎么指的进行操作在主循环的每次迭代之间还添加了一个延时。

使用Arduino IDE编译并上传代码即可对其进行测试。然后打开serial monitor,將其波特率设为begin函数中指定的数值(115200)您将看到类似图1的输出结果,主循环每次迭代都会将插入到队列指针是怎么指的中的数据项打印絀来

图1 - 队列指针是怎么指的例程输出

注:本文作者是Nuno Santos,他是一位和蔼可亲的电子和计算机工程师住在葡萄牙里斯本 (Lisbon)。

他写了很多有关ESP32、ESP8266的有用的教程和项目

查看更多ESP32/ESP8266教程和项目,请点击 : 汇总贴

}

我要回帖

更多关于 队列指针是怎么指的 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信