目录
一、FreeRTOS介绍
RTOS的全称是Real time operating system,中文就是实时操作系统。这里的RTOS不是指某一个确定的系统,而是指一类操作系统。比如:uc/OS,FreeRTOS,RTX, RT-Thread等这些都是RTOS类操作系统。
我们之所以选择FreeRTOS有以下几点原因;
·FreeRTOS是免费的;
·很多半导体厂商产品的SDK(Software Development Kit)软件开发工具包,就使用FreeRTOS 作为其操作系统,尤其是WIFI、蓝牙这些带有协议栈的芯片或模块。
·简单,因为FreeRTOS的文件数量很少。
二、FreeRTOS实现了什么功能
假设一个母亲在家带孩子,她需要完成给孩子喂饭和回同事信息两个任务;
裸机开发:
·回同事信息,导致孩子没吃上饭
·喂孩子吃饭,导致同事觉得被忽略
FreeRTOS:
一只手给同事回消息,一只手给孩子喂饭,虽然不能真正的同时运行,但喂一口饭后回一个信息在我们看来好像是同时运行的,这就是FreeRTOS所实现的功能:严格来说 FreeRTOS 并不是实时操作系统,因为它是分时复用的。 系统将时间分割成很多时间片,然后轮流执行各个任务。 每个任务都是独立运行的,互不影响,由于切换的频率很快,就感觉像是同时运行的一样。
三、使用CubeMX快速移植FreeRTOS
1. 在 SYS 选项里,将 Debug 设为 Serial Wire ,并且将 Timebase Source 设为 TIM2 (其它定时器也行)。
Timebase Source 为什么不能设置为 SysTick ? 裸机的时钟源默认是 SysTick,但是开启 FreeRTOS 后,FreeRTOS会占用 SysTick (用来生成1ms 定时,用于任务调度),所以需要为其他总线提供另外的时钟源。
2. 将 RCC 里的 HSE 设置为 Crystal/Ceramic Resonator 。
3. 选择 FREERTOS 选项,并将 Interface 改为 CMSIS_V1 。
FreeRTOS 版本问题:V2 的内核版本更高,功能更多,在大多数情况下 V1 版本的内核完全够用。
FreeRTOS 各配置选项卡的解释:
Events:事件相关的创建
Task and Queues: 任务与队列的创建
Timers and Semaphores: 定时器和信号量的创建
Mutexes: 互斥量的创建
FreeRTOS Heap Usage: 用于查看堆使用情况
Config parameters: 内核参数设置,用户根据自己的实际应用来裁剪定制FreeRTOS 内核
Include parameters: FreeRTOS 部分函数的使能
User Constants: 相关宏的定义,可以自建一些常量在工程中使用
Advanced settings:高级设置
四、任务的创建
1.什么是任务?
任务可以理解为进程/线程,创建一个任务,就会在内存开辟一个空间。
比如:给孩子喂饭,回同事信息,都可以视为任务
Windows 系统中的 MarkText 、谷歌浏览器、记事本,都是任务。
任务通常都含有 while(1) 死循环。
在FreeRTOS中,任务就是一个函数,原型如下:
下面是一个示例:
2.任务创建与删除的相关函数
任务动态创建与静态创建的区别: 动态创建任务的堆栈由系统分配,而静态创建任务的堆栈由用户自己传递。 通常情况下使用动态方式创建任务。
xTaskCreate 函数原型:
参数说明:
五、基于官方源码的示例
任务1的代码:
void vTask1( void *pvParameters )
{
const char *pcTaskName = "T1 run\r\n";
volatile uint32_t ul; /* volatile用来避免被优化掉 */
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务1的信息 */
printf( pcTaskName );
/* 延迟一会(比较简单粗暴) */
for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
}
}
}
任务2打印"T2 run\r\n";
main函数:
int main( void )
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
运行结果如下:
注意:
·task 2先运行!
·要分析xTaskCreate的代码才能知道原因:更高优先级的、或者后面创建的任务先运行。
任务运行图:
·在t1:Task2进入运行态,一直运行直到t2
·在t2:Task1进入运行态,一直运行直到t3;在t3,Task2重新进入运行态
六、基于CubeMX移植RTOS的示例
用CubeMX生成FreeRTOS的代码后,转到freertos.c
这里CubeMX自动帮我们封装好了xTaskCreate和调度函数vTaskStartScheduler();在CubeMX中被封装成osKernelStart();这里任务函数的osDelay是自动生成好的;
上图是在CubeMX里配置相关参数封装的xTaskCreate函数;
在CubeMX的FreeRTOS选项选择Tasks and Queues选项卡,点击Add可以自定义任务:
在任务函数里编写想要实现的功能就可以直接编译下载。
七、任务删除(补充)
删除任务时使用下面这个函数
void vTaskDelete( TaskHandle_t xTaskToDelete );
参数说明:
怎么删除任务?举个不好的例子:
·自杀: vTaskDelete(NULL)
·被杀:别的任务执行 vTaskDelete(pvTaskCode) ,pvTaskCode是自己的句柄
·杀人:执行 vTaskDelete(pvTaskCode) ,pvTaskCode是别的任务的句柄
注意:对于自杀的任务,由空闲函数来释放他的内存,对于被杀的任务,由凶手来释放他的内存!!!所以如果编写程序时用了自杀的方式来删除任务,一定要让空闲任务运行(优先级为0),以免内存不足,创建任务失败!!!
八、总结
本文章概述了FreeRTOS的基本概念和功能以及内部实现的方式,还给了两个基于不同源码的示例,用CubeMX生成代码更加方便,但学习官方源码能更好的理解底层逻辑,后续我会继续更新我的FreeRTOS学习笔记。