基於Arduino的RTOS入門
RTOS代表**即時作業系統**。它用於併發執行多個任務,按需排程任務,並使它們能夠共享資源。雖然本文不詳細介紹RTOS的細節,但我們將逐步講解一個示例,讓您對RTOS有一個大致瞭解。目前,您只需注意,RTOS 將幫助您在 Arduino 中執行多工處理,就像您計算機上的作業系統幫助您同時執行多個任務(例如撰寫郵件、收聽音樂等)一樣。
由於我們關注的是微控制器,我們將使用**FreeRTOS**,這是一個用於嵌入式裝置的RTOS。基本上,它設計得足夠小,可以支援微控制器。您可以在此處閱讀更多關於 FreeRTOS 的資訊:https://en.wikipedia.org/wiki/FreeRTOS
現在,要在Arduino上開始使用FreeRTOS,我們首先需要一個外部庫。轉到**工具 -> 管理庫**,然後搜尋**FreeRTOS**。
您將看到Richard Barry的庫。如前所述,它適用於**Uno**、**Nano**、**Leonardo**和**Mega**開發板。我們使用的是Uno開發板,因此我們將安裝此庫。
庫安裝完成後,您將能夠在**檔案 -> 示例**中看到與該庫相關的所有示例程式碼。
建議您仔細閱讀所有示例以進一步瞭解FreeRTOS。我們將逐步講解其中一個示例:**Blink_AnalogRead**。
如您所見,我們首先包含庫
#include <Arduino_FreeRTOS.h>
之後,我們宣告兩個任務:Blink任務和AnalogRead任務。
void TaskBlink( void *pvParameters ); void TaskAnalogRead( void *pvParameters );
請注意,它接收**pvParameters**指標作為輸入。我們稍後會再討論這一點。
接下來是重要的設定部分。
示例
// the setup function runs once when you press reset or power the board void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards. } // Now set up two tasks to run independently. xTaskCreate( TaskBlink , "Blink" // A name just for humans , 128 // This stack size can be checked & adjusted by reading the Stack Highwater , NULL , 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. , NULL ); xTaskCreate( TaskAnalogRead , "AnalogRead" , 128 // Stack size , NULL , 1 // Priority , NULL ); // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started. }
請注意此部分中的所有註釋。
我們首先初始化序列埠,然後等待其初始化。
然後,我們使用xTaskCreate建立任務。xTaskCreate的語法如下:
語法
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,const char * const pcName,configSTACK_DEPTH_TYPE usStackDepth,void *pvParameters, UBaseType_t uxPriority,TaskHandle_t *pxCreatedTask);
- **pvTaskCode**是執行任務的函式名稱(**TaskBlink**和**TaskAnalogRead**)。
- **pcName**是任務的名稱(如註釋中所述,僅供人類參考)。
- **usStackDepth**是分配給任務堆疊的字數。請參考您的開發板的資料手冊以確定一個字等於多少位元組。
- **pvParameters**是要傳遞給已建立任務的引數。還記得在宣告任務時使用的**pvParameters**引數嗎?它們就是從這裡來的。例如,您想向任務傳遞數字1,可以透過將(void *) 1傳遞給**xTaskCreate**的**pvParameters**引數來實現。
- **uxPriority**定義任務的優先順序。數字越大,優先順序越高。
- **pxCreatedTask**是任務控制代碼。這是可選的,您可以傳入NULL。它的目的是在程式碼的其他部分引用任務。
建立任務後,如註釋中所述,任務排程程式會自動啟動。接下來,我們的迴圈為空,因為我們在任務中執行程式碼。
最後,定義了兩個任務的函式。
示例
void TaskBlink(void *pvParameters) // This is a task. { (void) pvParameters; /* Blink Turns on an LED on for one second, then off for one second, repeatedly. Most Arduinos have an on-board LED you can control. On the UNO, LEONARDO, MEGA, and ZERO, it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN takes care of use the correct LED pin whatever is the board used. The MICRO does not have a LED_BUILTIN available. For the MICRO board please substitute the LED_BUILTIN definition with either LED_BUILTIN_RX or LED_BUILTIN_TX. e.g. pinMode(LED_BUILTIN_RX, OUTPUT); etc. If you want to know what pin the on-board LED is connected to on your Arduino model, check the Technical Specs of your board at https://www.arduino.cc/en/Main/Products This example code is in the public domain. modified 8 May 2014 by Scott Fitzgerald modified 2 Sep 2016 by Arturo Guadalupi */ // initialize digital LED_BUILTIN on pin 13 as an output. pinMode(LED_BUILTIN, OUTPUT); for (;;) // A Task shall never return or exit. { digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second } } void TaskAnalogRead(void *pvParameters) // This is a task. { (void) pvParameters; /* AnalogReadSerial Reads an analog input on pin 0, prints the result to the serial monitor. Graphical representation is available using serial plotter (Tools > Serial Plotter menu) Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground. This example code is in the public domain. */ for (;;) { // read the input on analog pin 0: int sensorValue = analogRead(A0); // print out the value you read: Serial.println(sensorValue); vTaskDelay(1); // one tick delay (15ms) in between reads for stability }
任務中的註釋很好地解釋了程式碼。請注意,在任務中,我們使用任務中的**vTaskDelay()**代替**delay()**。**vTaskDelay(1)** 引入 1 個 tick 的延遲。1 個 tick 可能對應 1ms,也可能不對應。如**AnalogRead**任務的註釋中所述,1 個 tick 對應 15ms。這取決於開發板的時鐘頻率。為了獲得以毫秒為單位的延遲時間,我們可以將毫秒時間除以**portTICK_PERIOD_MS**常量。如**TaskBlink**中所做的那樣,1 秒的延遲透過以下命令實現:**vTaskDelay( 1000 / portTICK_PERIOD_MS );**
您可以在此處閱讀更多關於 freeRTOS 的資訊:https://www.freertos.org/