查看: 261|回复: 0

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

[复制链接]
  • TA的每日心情

    2018-1-11 13:58
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    发表于 2019-5-16 10:24 | 显示全部楼层 |阅读模式
    本 esp32 arduino 教程的目的是解释如何在 freertos 队列的前面和后面插入内容。此 esp32 教程的测试是使用集成在esp32 开发板中的dfrobot 的 [url=http://www.dfrobot.com.cn/goods-1359.html]esp32[/url] 模块设备进行的。


    引言
    本文主要说明如何在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提供的不同插入方法,我们将创建两个队列,一个用于在前面插入数据,另一个用于在后面插入数据。这些队列将分别保存在下面声明的两个全局变量中。

    QueueHandle_t queueBack; QueueHandle_t queueFront;

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

    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");   } }



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

    kittenblock中小学创客名师推荐的图形化编程软件

    
    for(int i = 0; i<10; i++){
    
        xQueueSendToBack(queueBack, &i, 0);
    
        xQueueSendToFront(queueFront, &i, 0);
    
      }
    
    


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

    kittenblock中小学创客名师推荐的图形化编程软件

    
    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("|");
    
    }
    
    
    完整的源代码如下所示。请注意,在每次循环时我们都加入了一个小的延时,并且对每个队列都进行了空队列检验。


    kittenblock中小学创客名师推荐的图形化编程软件

    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);
    
    }
    
    
    
    



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



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

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



    打赏作者鼓励一下!
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    Arduino lcd屏幕亮了但是不显示字符
    Arduino lcd屏幕亮了但是
    Arduino的lcd屏亮了但是上面没有字符显示,串进去的滑动变阻器也旋过了,但是还是没有
    【原创】全球最小口袋3D打印机mini one直播教程贴
    【原创】全球最小口袋3D打
    最近闲得蛋疼,没事搞个掌上3D打印机,先放效果图吧。 搞了半天,终于能正常打印,
    [限时福利]5分钟带你快速了解新一代开发板:M5STACK
    [限时福利]5分钟带你快速
    一、什么是M5Stack M5Stack是一种模块化、可堆叠扩展的开发板,每个模块
    【Arduino】108种传感器模块系列实验(98)---L298N电机驱动板
    【Arduino】108种传感器模
    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是
    两个ESP8266通过云端实现远程数据交互
    两个ESP8266通过云端实现
    原理简述:利用发布订阅模式。一个ESP8266作为消息发布者,另一个ESP8266作为消息订阅
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表