引言 尽管队列通常用于任务间通信,但是我们将在主循环中进行测试,因为我们的目标是对在前面和后面插入数据以及相应所需要的API调用进行比较。
代码 为了能更轻松地比较FreeRTOS API提供的不同插入方法,我们将创建两个队列,一个用于在前面插入数据,另一个用于在后面插入数据。这些队列将分别保存在下面声明的两个全局变量中。
[mw_shl_code=applescript,true] QueueHandle_t queueBack;
QueueHandle_t queueFront;
[/mw_shl_code]
在设置函数中,我们将打开一个串行连接,以便稍后打印输出结果。在代码执行时,可以在Arduino IDE Serial Monitor中对其进行分析。 该函数若执行成功,将会返回所创建的队列句柄,这个句柄将被保存到我们的全局变量中。如果队列未能成功创建,则函数将会返回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函数时,它的第一个参数是要消耗的队列句柄,第二个参数是一个指针,指向用于存储消耗数据项的缓冲区,第三个参数是当队列为空时的等待时间。最后一个参数直接给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所示的输出。第一个队列的元素在打印时顺序与插入时的顺序一致。第二个队列的元素则是相反的顺序。
图1 - 在FreeRTOS队列后面/前面插入数据的程序输出结果。
查看更多ESP32/ESP8266教程和项目,请点击 : ESP32教程汇总贴
|