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

     

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章