我们从一开始接触Arduino编程就知道,Arduino程序结构由setup()和loop()两部分组成,我们需要反复执行的代码要放在loop()中,并且这些代码一般都是顺序执行的。
随着我们需要实现的功能越来越复杂,这种顺序执行的方式很难达到实时性,这个时候就需要使用操作系统了,就类似于我们的PC机,可以同时运行多个软件,你可以一边聊QQ一边看电影,或者你用手机一边听歌一边看这篇文章。当然PC机和手机的处理器要强大的太多太多了,而我们的Arduino UNO开发板上使用的是一颗8位的AVR单片机。
接触过嵌入式的朋友都知道,我们会在ARM处理器上使用Linux系统,而在STM32这种较ARM低端而又比单片机强大的MCU上一般会使用更轻量级的实时操作系统,类似的如UCOS、FreeRTOS、RTThread等。习惯了STM32上运行FreeRTOS,真的没有想过在Arduino上来运行,最近发现了被移植到Arduino上运行的FreeRTOS实时操作系统,赶紧来尝试下。
在Arduino IDE中,点击「项目」—「加载库」—「管理库」,在搜索栏输入"FreeRTOS",查找并安装库。
Arduino FreeRTOS库可运行于Arduino AVR设备,如Uno、Leonardo、Mega等。本篇使用Uno开发板。
首先要包含Arduino FreeRTOS库的头文件。
#include
我们使用xTaskCreate()函数来创建任务,函数原型为:
xTaskCreate(TaskFunction_t pvTaskCode,const char * const pcName,uint16_t usStackDepth,void * pvParameters,UBaseType_t uxPriority,TaskHandle_t * pxCreatedTask)
创建任务时需要传入6个参数:
本次实验创建两个串口打印任务:
xTaskCreate(TaskPrint1, "Print1", 128, NULL, 1, NULL);
xTaskCreate(TaskPrint2, "Print2", 128, NULL, 2, NULL);
其中任务2有更高的优先级,会首先执行。
创建任务后,使用**vTaskStartScheduler()**函数启动任务调度。
创建任务实现函数。一般结构如下:
void task(void *param)
{
while(1)
{
....//需要执行的代码
}
}
大多数代码都需要延迟函数来停止正在运行的任务,但是在RTOS中,不建议使用**Delay()**函数,因为它会停止CPU,因此RTOS也将停止工作。因此,FreeRTOS具有内核API,可以在特定时间内阻止任务:
vTaskDelay(const TickType_t xTicksToDelay)
例如延时1秒:
vTaskDelay(1000 / portTICK_PERIOD_MS)
其中portTICK_PERIOD_MS与实际MCU的时钟频率相关。
#include
void TaskPrint1(void *param); //声明打印任务1
void TaskPrint2(void *param); //声明打印任务2
void setup() {
Serial.begin(9600);
while (!Serial);//等待串口连接后执行
xTaskCreate(TaskPrint1, "Print1", 128, NULL, 1, NULL); //创建任务1
xTaskCreate(TaskPrint2, "Print2", 128, NULL, 2, NULL); //创建任务2
vTaskStartScheduler(); //启动任务调度
}
void TaskPrint1(void *param)
{
while (1)
{
Serial.println("TaskPrint1...");
vTaskDelay(1000 / portTICK_PERIOD_MS ); // 等待1秒
}
}
void TaskPrint2(void *param)
{
while (1)
{
Serial.println("TaskPrint2...");
vTaskDelay(2000 / portTICK_PERIOD_MS ); // 等待2秒
}
}
void loop() {
}
打开串口监视器,波特兰设置与程序中一致的9600,会看到任务2先运行打印,由于任务1等待1秒,任务2等待2秒,所以每次打印任务1两次,打印任务2一次。
关注公众号「TonyCode」,回复「1024」获取1000G学习资料。
个人博客