☛ 功能说明
利用 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 );