基于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/

更新于:2021年3月24日

968 次浏览

开启您的职业生涯

完成课程获得认证

开始学习
广告