Bootstrap

《ESP32 学习笔记》 之Arduino环境下 使用 FreeRTOS 操作系统

  • 在刚开始学习 arduino 时,当时想让几个灯以不同的频率闪烁,找遍了网上,也没找到可以实现的方法,后来学习 STM32 后,定时器操作勉强可以达到想要的多任务效果,但也不尽人意,直到了解到 STM32 可以跑系统,才知道单片机也可以这么玩。后来从ESP8266到ESP32,了解到ESP32的超强内核,内嵌 FreeRTOS 操作系统,有了这一功能,我们可以轻易完成当初的想法。
  • FreeRTOS 不仅可以在SDK编程中可以使用,Arduino 中也支持FreeRTOS 的一系列操作。
  • 此博文主要记录学习过程的心得体会和程序代码,以供后续项目使用!
  • 学习地址:DFROBOT官网
  • ESP32-IDF 官方讲解FreeRTOShttp://esp32.info/docs/esp_idf/html/dd/d3c/group__xTaskCreate.html
  • FreeRTOS官网:https://www.freertos.org/a00125.html
  1. 创建 FreeRTOS 任务:
    /*
    @功能:创建多任务
    @时间:2020/3/5
    @作者:刘泽文
    @QQ:2822604962
    */
    #include <WiFi.h>
    
    #define LED1 19
    #define LED2 22
    #define LED1_OFF   digitalWrite(LED1, HIGH)//关灯
    #define LED1_ON    digitalWrite(LED1, LOW)//开灯
    #define LED1_PWM   digitalWrite(LED1, !digitalRead(LED1))//灯闪烁
    #define LED2_OFF   digitalWrite(LED2, HIGH)//关灯
    #define LED2_ON    digitalWrite(LED2, LOW)//开灯
    #define LED2_PWM   digitalWrite(LED2, !digitalRead(LED2))//灯闪烁
    
    void taskOne( void * parameter ){
      while(1){
        delay(200);
        LED1_PWM;
      }
      Serial.println("Ending task 1");
      vTaskDelete( NULL );
    }
    
    void taskTwo( void * parameter){
      while(1){
        delay(400);
        LED2_PWM;
      }
      Serial.println("Ending task 2");
      vTaskDelete( NULL );
    }
    
    void taskThree( void * parameter){
      while(1){
        delay(800);
        LED1_PWM;
        LED2_PWM;
      }
      Serial.println("Ending task 3");
      vTaskDelete( NULL );
    }
    
    
    void setup() {
      Serial.begin(115200);
      pinMode(LED1,OUTPUT);
      pinMode(LED2,OUTPUT);
      LED1_OFF;
      LED2_OFF;
      delay(1000);
      xTaskCreate(
                  taskOne,          /*任务函数*/
                  "TaskOne",        /*带任务名称的字符串*/
                  10000,            /*堆栈大小,单位为字节*/
                  NULL,             /*作为任务输入传递的参数*/
                  1,                /*任务的优先级*/
                  NULL);            /*任务句柄*/
      xTaskCreate(
                  taskTwo,          /* Task function. */
                  "TaskTwo",        /* String with name of task. */
                  10000,            /* Stack size in bytes. */
                  NULL,             /* Parameter passed as input of the task */
                  1,                /* Priority of the task. */
                  NULL);            /* Task handle. */
      xTaskCreate(
                  taskThree,          /* Task function. */
                  "taskThree",        /* String with name of task. */
                  10000,            /* Stack size in bytes. */
                  NULL,             /* Parameter passed as input of the task */
                  1,                /* Priority of the task. */
                  NULL);            /* Task handle. */
    }
     
    void loop(){
      delay(1000);
    }
     

     

  2. 查询 FreeRTOS 任务优先级:
    /*
    @功能:查询任务优先级
    @时间:2020/3/5
    @作者:刘泽文
    @QQ:2822604962
    */
    #include <Arduino.h>
    
    #define LED1 19
    #define LED1_OFF   digitalWrite(LED1, HIGH)//关灯
    #define LED1_ON    digitalWrite(LED1, LOW)//开灯
    #define LED1_PWM   digitalWrite(LED1, !digitalRead(LED1))//灯闪烁
    
    void taskOne( void * parameter ){
      while(1){
        delay(200);
        LED1_PWM;
      }
      Serial.println("Ending task 1");
      vTaskDelete( NULL );
    }
    
    void setup(void) 
    {
      Serial.begin(115200);
      pinMode(LED1,OUTPUT);
      LED1_OFF;
      delay(500);
      TaskHandle_t myTask;//声明一个TaskHandle_t类型的变量,用于存储将要新建的任务的句柄
      xTaskCreate(
                  taskOne,          /*任务函数*/
                  "TaskOne",        /*带任务名称的字符串*/
                  10000,            /*堆栈大小,单位为字节*/
                  NULL,             /*作为任务输入传递的参数*/
                  6,                /*任务的优先级*/
                  &myTask);            /*任务句柄*/
      Serial.print("taskOne任务的优先级 = ");
      Serial.println(uxTaskPriorityGet(myTask));
    }
    
    void loop(void)
    {
      delay(1000);
      Serial.print("loop()任务的优先级 = ");
      Serial.println(uxTaskPriorityGet(NULL));
    }

     

  3. FreeRTOS 队列:
    /*
    @功能: 队列测试
    @时间:2020/3/5
    @作者:刘泽文
    @QQ:2822604962
    */
    #include <Arduino.h>
    
    QueueHandle_t queue;
      
    void setup() {
      
      Serial.begin(115200);
      
      queue = xQueueCreate( 10, sizeof( int ) );//创建队列
      
      if(queue == NULL){
        Serial.println("Error creating the queue");
      }
      
    }
      
    void loop() {
      
      if(queue == NULL)return;
      
      for(int i = 0; i<10; i++){
        xQueueSend(queue, &i, portMAX_DELAY);//向队列尾部插入数值
      }
      
      int element;
      Serial.println("xQueueReceive 函数读取结果:");
      for(int i = 0; i<10; i++){
        xQueueReceive(queue, &element, portMAX_DELAY);//读取队列值,并从队列中移除
        Serial.print(element);
        Serial.print("|");
      }
      Serial.println("");
    
      delay(1000);
    }

     

  4. FreeRTOS 队列性能测试:
    /*
    @功能: 队列性能测试
    @时间:2020/3/5
    @作者:刘泽文
    @QQ:2822604962
    */
    #include <Arduino.h>
    
    QueueHandle_t queue;//新建队列
    int queueSize = 10000;//队列大小
    //被赋值系统时间的一些变量
    unsigned long startProducing, endProducing, startConsuming, endConsuming, producingTime, consumingTime; 
    
    void producerTask( void * parameter )
    {
        startProducing = millis();//开始时间
      
        for( int i = 0;i<queueSize;i++ ){
          xQueueSend(queue, &i, portMAX_DELAY);//写入队列值
        }
      
        endProducing = millis();//结束时间
      
        vTaskDelete( NULL );
      
    }
      
    void consumerTask( void * parameter)
    {
        startConsuming = millis();//开始时间
      
        int element;
      
        for( int i = 0; i<queueSize; i++ ){
            xQueueReceive(queue, &element, portMAX_DELAY);//读取队列值
        }
      
        endConsuming = millis();//结束时间
      
        vTaskDelete( NULL );
      
    }
    
    void setup() {
      
      Serial.begin(115200);
      
      queue = xQueueCreate( queueSize, sizeof( int ) );//设置队列大小
      
      if(queue == NULL){
        Serial.println("Error creating the queue");
      }
      
      xTaskCreate(
                        producerTask,     /* Task function. */
                        "Producer",       /* String with name of task. */
                        10000,            /* Stack size in words. */
                        NULL,             /* Parameter passed as input of the task */
                        10,               /* Priority of the task. */
                        NULL);            /* Task handle. */
      
      xTaskCreate(
                        consumerTask,     /* Task function. */
                        "Consumer",       /* String with name of task. */
                        10000,            /* Stack size in words. */
                        NULL,             /* Parameter passed as input of the task */
                        10,               /* Priority of the task. */
                        NULL);            /* Task handle. */
      
        producingTime = endProducing - startProducing;
        Serial.print("Producing time: ");
        Serial.println(producingTime);//写入耗费时间(ms)
      
        consumingTime = endConsuming - startConsuming;
        Serial.print("Consuming time: ");
        Serial.println(consumingTime);//读取耗费时间(ms)
    }
      
    void loop() {
      delay(1000);
    }

     

  5. 使用 FreeRTOS 队列实现任务之间的通信:(队列的元素可以改为结构体试试哦~)
    /*
    @功能: 两个不同的任务之间进行通信
    @时间:2020/3/11
    @作者:刘泽文
    @QQ:2822604962
    */
    #include <WiFi.h>
    
    QueueHandle_t queue;//新建队列
    int queueSize = 40;//队列大小
     
    void producerTask( void * parameter )
    {
        while(true){
          for( int i = 0;i<queueSize;i++ ){
            xQueueSend(queue, &i, portMAX_DELAY);//写入队列值
          }
          delay(1000);
        }
        vTaskDelete(NULL);
    }
      
    void consumerTask( void * parameter)
    {
        int element;
        while(true){
          for( int i = 0; i<queueSize; i++ ){
            xQueueReceive(queue, &element, portMAX_DELAY);//读取队列值
            Serial.print(element);//打印出来
            Serial.print("|");
          }
          Serial.println("");
          delay(1000);
        }
        vTaskDelete( NULL );
    }
     
    void setup() {
      Serial.begin(9600);
    
      queue = xQueueCreate( queueSize, sizeof( int ) );//设置队列大小
    
      if(queue == NULL){
        Serial.println("Error creating the queue");
      }
    
      xTaskCreate(
                        producerTask,     /* Task function. */
                        "Producer",       /* String with name of task. */
                        10000,            /* Stack size in words. */
                        NULL,             /* Parameter passed as input of the task */
                        1,               /* Priority of the task. */
                        NULL);            /* Task handle. */
      
      xTaskCreate(
                        consumerTask,     /* Task function. */
                        "Consumer",       /* String with name of task. */
                        10000,            /* Stack size in words. */
                        NULL,             /* Parameter passed as input of the task */
                        1,               /* Priority of the task. */
                        NULL);            /* Task handle. */
    }
      
    void loop() {
      delay(1000);
    }

     

  6. 在 FreeRTOS 队列前/后插入数据:
    /*
    @功能: 在队列的前后插入数据
    @时间:2020/3/11
    @作者:刘泽文
    @QQ:2822604962
    */
    #include <WiFi.h>
    
    //新建队列,测试两个插入函数
    QueueHandle_t queueBack;
    QueueHandle_t queueFront;
    
    void setup() {
      Serial.begin(9600);
    
      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("queueBack队列:");
      //读取queueBack队列的值
      for(int i = 0; i<10; i++){
        xQueueReceive(queueBack, &element, 0);
        Serial.print(element);
        Serial.print("|");
      }
      Serial.println();
    
      Serial.println("queueFront队列:");
      //读取queueFront队列的值
      for(int i = 0; i<10; i++){
        xQueueReceive(queueFront, &element, 0);
        Serial.print(element);
        Serial.print("|");
      }
      Serial.println();
      Serial.println("-------完成-------");
      delay(1000);
    }

     

 

;