2019-1-29 10:21:36 [显示全部楼层]
5170浏览
查看: 5170|回复: 1

[ESP32系列教程] ESP32 Arduino教程:在FreeRTOS队列前/后插入数据

[复制链接]
本 esp32 Arduino 教程的目的是解释如何在 freertos 队列的前面和后面插入内容。此 esp32 教程的测试是使用集成在esp32 开发板中的dfrobot 的 esp32]esp32模块设备进行的。


引言
本文主要说明如何在FreeRTOS队列前/后插入数据。有关在ESP32上使用FreeRTOS队列的入门教程,请参见这一篇文章:ESP32 Arduino教程:FreeRTOS队列
尽管队列通常用于任务间通信,但是我们将在主循环中进行测试,因为我们的目标是对在前面和后面插入数据以及相应所需要的API调用进行比较。
有关队列的教程中,我们使用了xQueueSend函数(https://www.freertos.org/a00117.html)在队列中插入数据项。该函数只能在队列的末尾插入数据项,其主要作用是为了兼容老版本的FreeRTOS[1]。
因此,为了更灵活地控制数据项的插入位置,本文将使用xQueueSendToBack函数(https://www.freertos.org/xQueueSendToBack.html)和xQueueSendToFront函数(https://www.freertos.org/xQueueSendToFront.html)分别在队列的后面和前面插入数据项。本教程将对这两个函数进行测试。


代码
为了能更轻松地比较FreeRTOS API提供的不同插入方法,我们将创建两个队列,一个用于在前面插入数据,另一个用于在后面插入数据。这些队列将分别保存在下面声明的两个全局变量中。

[mw_shl_code=applescript,true]
QueueHandle_t queueBack;

QueueHandle_t queueFront;

[/mw_shl_code]
在设置函数中,我们将打开一个串行连接,以便稍后打印输出结果。在代码执行时,可以在Arduino IDE Serial Monitor中对其进行分析。
接下来,我们将调用xQueueCreate函数(https://www.freertos.org/a00116.html)以对每个队列进行初始化。该函数的第一个参数是在一定时间内队列所能保存的最大数据项个数,第二个参数是每个数据项的大小(以字节表示)。此处我们使用最多10个数据项的简单整数队列。关于该函数(https://techtutorialsx.com/2017/ ... no-freertos-queues/)的详细说明,请参见上一篇教程:ESP32 Arduino教程:FreeRTOS队列
该函数若执行成功,将会返回所创建的队列句柄,这个句柄将被保存到我们的全局变量中。如果队列未能成功创建,则函数将会返回NULL,我们需要检查问题出在了哪里,并在队列初始化失败时打印出相关消息。在本例中,哪一个队列创建失败其实无关紧要,因为不管是哪一个队列出现了错误,我们都将终止程序运行。

[mw_shl_code=applescript,true]
void setup() {



  Serial.begin(115200);



  queueBack = xQueueCreate( 10, sizeof( int ) );

  queueFront = xQueueCreate( 10, sizeof( int ) );



  if(queueBack == NULL || queueFront == NULL){

    Serial.println("Error creating one of the queues");

  }

}

[/mw_shl_code]


每个队列的数据项插入操作都在Arduino主循环内执行。对于第一个队列,我们将使用xQueueSendToBack函数在队列后面插入数据项。对于第二个队列,我们将使用xQueueSendToFront函数在队列前面插入数据项。
请注意,这两个函数使用完全相同的参数,唯一的不同就是数据项在队列中的插入位置。
因此,这两个函数的输入参数都是三个,第一个是队列句柄,第二个是指向待插入数据项的指针(复制而非引用),第三个是当队列已满时任务需要等待的时间间隔(时钟计数值,以tick表示)。
我们将使用循环在每个队列中都插入10个数据,这是我们在每个队列初始化时指定的最大数据项个数。
每个函数都有三个参数,第一个参数是全局队列句柄,第二个参数是指向当前数据项的整数指针,最后一个参数我们直接给0,因为本文的程序设计能够确保不会发生向满队列插入数据的情况。需要注意的是,该参数如果是0,那么即使队列已满,任务也不会等待,而是会继续执行。

[mw_shl_code=applescript,true]
for(int i = 0; i<10; i++){

    xQueueSendToBack(queueBack, &i, 0);

    xQueueSendToFront(queueFront, &i, 0);

  }

[/mw_shl_code]


接下来,我们通过调用xQueueReceive函数(https://www.freertos.org/a00118.html)来消耗队列中的数据项。我们无法指定是从前面还是后面消耗队列中的数据项,因此一般都是从队列前面取出数据。
我们需要一个用于保存所消耗数据项的缓冲区,所以在从队列中读取数据之前,我们要先声明一个整数变量。然后,在两个不同的循环中从各自队列消耗数据即可。
在调用xQueueReceive函数时,它的第一个参数是要消耗的队列句柄,第二个参数是一个指针,指向用于存储消耗数据项的缓冲区,第三个参数是当队列为空时的等待时间。最后一个参数直接给0。
我们先读取从后面插入新元素的队列。其遵循FIFO(先入先出)原则,所以打印出的元素顺序与插入顺序是一致的。
然后我们读取从前面插入新元素的队列。其遵循LIFO(后入先出)原则,所以最后插入的元素将被最先取出。

[mw_shl_code=applescript,true]
int element;



Serial.println("Back queue:");



for(int i = 0; i<10; i++){

    xQueueReceive(queueBack, &element, 0);

    Serial.print(element);

    Serial.print("|");

}

Serial.println();

Serial.println("Front queue:");



for(int i = 0; i<10; i++){

    xQueueReceive(queueFront, &element, 0);

    Serial.print(element);

    Serial.print("|");

}

[/mw_shl_code]

完整的源代码如下所示。请注意,在每次循环时我们都加入了一个小的延时,并且对每个队列都进行了空队列检验。


[mw_shl_code=applescript,true]QueueHandle_t queueBack;

QueueHandle_t queueFront;



void setup() {



  Serial.begin(115200);



  queueBack = xQueueCreate( 10, sizeof( int ) );

  queueFront = xQueueCreate( 10, sizeof( int ) );



  if(queueBack == NULL || queueFront ==NULL){

    Serial.println("Error creating one of the queues");

  }



}



void loop() {



  if(queueBack == NULL || queueFront == NULL )return;



  for(int i = 0; i<10; i++){

    xQueueSendToBack(queueBack, &i, 0);

    xQueueSendToFront(queueFront, &i, 0);

  }



  int element;



  Serial.println("Back queue:");



  for(int i = 0; i<10; i++){

    xQueueReceive(queueBack, &element, 0);

    Serial.print(element);

    Serial.print("|");

  }

Serial.println();

  Serial.println("Front queue:");



  for(int i = 0; i<10; i++){

    xQueueReceive(queueFront, &element, 0);

    Serial.print(element);

    Serial.print("|");

  }

Serial.println();

  Serial.println("--------------");

  delay(1000);

}



[/mw_shl_code]


测试代码
要对代码进行测试,只需使用Arduino IDE对其进行编译并上传到开发板即可。然后,打开IDE Serial Monitor观察运行结果。
您应该看到如图1所示的输出。第一个队列的元素在打印时顺序与插入时的顺序一致。第二个队列的元素则是相反的顺序。


ESP32 Arduino教程:在FreeRTOS队列前/后插入数据图1

图1 - 在FreeRTOS队列后面/前面插入数据的程序输出结果。


注:本文作者是Nuno Santos,他是一位和蔼可亲的电子和计算机工程师,住在葡萄牙里斯本 (Lisbon)。
他写了200多篇有关ESP32、ESP8266的有用的教程和项目,涉及技术使用范围包括:arduino、JSON、WI-FI、SHA-256、Picoweb、FreeRTOS队列…。

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

gada888  版主

发表于 2019-2-1 13:45:58

支持
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail