☛ 功能说明

利用 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");  
           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 );