☛ 功能說明

利用 Arduino UNO 開發板及 FreeRTOS 函式庫控制兩個 LED 同時以不同頻率閃爍,並且透過 Serial Monitor 觀察每一個時間兩個任務 ( Tash ) 的運行狀況。

☛ 使用材料

Arduino UNO R3 開發板 × 1、LED × 2、電阻 220Ω × 2。

☛ 電路圖及麵包板接線圖

☛ 程式碼

#include<Arduino_FreeRTOS.h>                          //引用 FreeRTOS 函式庫

void Task1( void *pvParameters );                     //宣告 Task1
void Task2( void *pvParameters );                     //宣告 Task2
void Taskprint( void *pvParameters );                 //宣告 Taskprint

void setup() 
{
     Serial.begin(9600);                              //設定串列埠鮑率為 9600 bps
     pinMode(9, OUTPUT);                              //數位接腳 9 連接至 LED1
     pinMode(10, OUTPUT);                             //數位接腳 10 連接至 LED2
     xTaskCreate(TaskBlink1,"Task1",128,NULL,1,NULL); //建立 Task1Blink1 任務
     xTaskCreate(TaskBlink2,"Task2",128,NULL,1,NULL); //建立 Task1Blink2 任務
     xTaskCreate(Taskprint,"Task3",128,NULL,1,NULL);  //建立 Taskprint 任務
     vTaskStartScheduler();                           //對所有任務 Task 進行任務排程
}

void loop()
{

}

void TaskBlink1(void *pvParameters)                   //LED1 閃爍頻率 200ms
{ 
     while(1)
     {
           digitalWrite(9, HIGH);                     //點亮 LED1
           vTaskDelay( 200 / portTICK_PERIOD_MS );    //延遲 200ms
           digitalWrite(9, LOW);                      //關閉 LED1
           Serial.println("Task1");                   //列印 Task1
           vTaskDelay( 200 / portTICK_PERIOD_MS );    //延遲 200ms
     }
}

void TaskBlink2(void *pvParameters)                   //LED2 閃爍頻率 500ms
{
     while(1)
     {
           digitalWrite(10, HIGH);                    //點亮 LED2
           vTaskDelay( 500 / portTICK_PERIOD_MS );    //延遲 500ms
           digitalWrite(10, LOW);                     //關閉 LED2
           Serial.println("Task2");                   //列印 Task2
           vTaskDelay( 500 / portTICK_PERIOD_MS );    //延遲 500ms
     }
}

void Taskprint(void *pvParameters)                    //輸出任務運行狀況至 Serial Monitor 視窗
{
     int counter = 0;                                 //循環計數
     while(1)
     {
          counter++;
          Serial.println(counter);                    //列印循環計數值
          vTaskDelay( 500 / portTICK_PERIOD_MS );     //延遲 500ms
     }
}

 

☛ 說明

FreeRTOS 多任務程式基本結構說明如下:

⑴ 首先,包含 Arduino FreeRTOS 檔。

⑵ 宣告所有要執行任務的函數的函數原型。 如下所示:

void Task1( void *pvParameters );
void Task2( void *pvParameters );

⑶ 在 void setup() 函數中,創建任務並啟動任務調度器。 創建任務,在 setup 函數中使用某些參數調用 API 函數 xTaskCreate()。

xTaskCreate( TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask );

參數說明如下:

① pvTaskCode:它只是實現任務的函數的指標。

② pcName:任務的描述性名稱。 FreeRTOS 不使用此功能。 純粹是出於調試目的將其包括在內。

③ usStackDepth:每個任務都有自己的唯一堆棧,內核在創建任務時將其分配給任務。 該值指定堆疊可以容納的字數,而不是位元組數。 例如,如果堆棧為 32 位寬,並且 usStackDepth 作為 100 傳入,那麼將在 RAM 中分配 400 位元組的堆疊空間 ( 100 * 4 位元組 )。

④ pvParameters:任務輸入參數 ( 可以為 NULL )。

⑤ uxPriority:任務的優先順序 ( 0是最低優先順序 )。

⑥ pxCreatedTask:可用於向正在創建的任務傳遞句柄。 然後,可以使用此句柄在 API 呼叫中引用工作,例如,更改工作優先順序或刪除工作 ( 可以為 NULL )。

⑷ 創建任務后,在 setup 函數中使用 vTaskStartScheduler() 中啟動調度程式。 ( 注意:所有的設定宣告,必須要寫在此調度程式之前,否則不會生效 )。 

⑸ loop() 函數將保持為空,因為任務執行現在由調度程序處理。

⑹ 現在,我們必須實現任務函數,並在這些函數內編寫要執行的邏輯。 函數名稱應與 xTaskCreate() 的第一個參數相同。

void task1(void *pvParameters)  
{
     while(1) 
     {
         //put your task code here, to run repeatedly: 
     }
}uu

⑺ 大多數代碼都需要延遲函數來停止正在運行的任務,但是在 RTOS 中,不建議使用 Delay() 函數,因為它會停止 CPU,因此 RTOS 也將停止工作。 因此,FreeRTOS 具有內核API,可以在特定時間內阻止任務。

vTaskDelay( const TickType_t xTicksToDelay );

該 API 可用於延遲目的。 此 API 將任務延遲給定的滴答數。 任務保持阻塞的實際時間取決於滴答率。 常量 portTICK_PERIOD_MS 可用於根據滴答率計算即時性。 這意味著如果您想要 200ms 的延遲,只需如下編寫。

vTaskDelay( 200 / portTICK_PERIOD_MS );