本文目的是在Keil uVision5(MDK)上把FreeRTOS移植到STM32平台上去,并练习使用FreeRTOS的任务调度功能
目录
(一)FreeRTOS简介
1.实时操作系统FreeRTOS
- 简介
- FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,其功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。
- RTOS 的任务调度器被设计为可预测的,而这正是嵌入式实时操作系统所需要的,实时环境中要求操作系统必须对某一个事件做出实时的响应,因此系统任务调度器的行为必须是可预测的。像FreeRTOS这种传统的 RTOS 类操作系统是由用户给每个任务分配一个任务优先级,任务调度器就可以根据此优先级来决定下一刻应该运行哪个任务。
- 相对μC/OS-II、embOS等商业付费操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以很方便地移植到各种单片机上运行。
- 特点
- FreeRTOS 的内核支持抢占式,合作式和时间片调度。
- 提供了一个用于低功耗的 Tickless 模式。
- 系统的组件在创建时可以选择动态或者静态的 RAM,比如任务、消息队列、信号量、软件定时器等等。
- FreeRTOS-MPU 支持 Corex-M 系列中的 MPU 单元,如STM32F103。
- FreeRTOS 系统简单、小巧、易用,通常情况下内核占用 4k-9k 字节的空间。
- 高可移植性,代码主要 C 语言编写。
- 任务与任务、任务与中断之间可以使用任务通知、消息队列、二值信号量、数值型信号量、递归互斥信号量和互斥信号量进行通信和同步,具有优先级继承特性的互斥信号量。
- 高效的软件定时器、强大的跟踪执行功能、堆栈溢出检测功能。
- 任务数量不限、任务优先级不限。
2.FreeRTOS源码分析
- 源码目录
FreeRTOS目录下主要包括Demo、Source文件夹,其中最重要的是Source文件夹。- Demo文件夹包含各种芯片的演示示例例程。
- Source文件夹包含FreeRTOS内核的源文件。
- FreeRTOS内核文件
可以看出Source文件夹下有include文件夹和portable文件夹以及一些C源文件,include文件夹主要是移植所需头文件,portable文件夹是连接软硬件的桥梁。FreeRTOS代码的核心包含在三个文件中:tasks.c、queue.c、list.c。除此之外还包含三个可选的文件:timers.c、event_groups.c、croutine.c,分别实现软件定时、事件组和协程功能。
(二)FreeRTOS移植到stm32
1.移植方法
网上已经有许多博主写得十分详细,我这里就不在赘述,详细移植步骤可参考下面这篇文章。
2.移植补充
- FreeRTOSConfig.h文件要从Demo文件夹下对应的芯片处理器例程中选取,比如说需要将FreeRTOS移植到Stm32上去,就需要将
Demo\CORTEX_STM32F103_Keil
路径下的FreeRTOSConfig.h头文件加入到工程中去。 - 需要修改startup_stm32f10x_hd.s文件中的内容
- 在__heap_limit的地方加入下面三条语句
IMPORT xPortPendSVHandler IMPORT xPortSysTickHandler IMPORT vPortSVCHandler
- 在__Vectors对应位置将图上对应的位置注释掉,加入如下三条语句
DCD vPortSVCHandler ;由FreeRTOS管理 DCD xPortPendSVHandler ;由FreeRTOS管理 DCD xPortSysTickHandler ;由FreeRTOS管理
- 移植结果
编译一下工程,结果如下:
0 Error(s),0 Warning(s),表明程序移植成功。接下来就是使用FreeRTOS的时候了,让我们去体验一下刚移植好的FreeRTOS吧。
(三)基于FreeRTOS的多任务程序
1.实验目的
基于刚移植好的FreeRTOS操作系统实现一个多任务程序,执行4个周期性的任务,具体任务如下:
task1:每间隔500ms闪烁(变化)一次LED0;
task2:每间隔1000ms闪烁(变化)一次LED1;
task3,每间隔2000ms,向串口发送一次指令数据hello LYJ!!!
;
task4,每间隔5000ms,从AHT20采集一次温湿度数据(不考虑硬件情况,仅写出整个多任务框架模拟代码)
2.实验主要代码
/*LED0周期性闪烁任务*/
void LED0Task(void *pvParameters)
{
while(1)
{
LED0=0;
printf("LED0亮\r\n");
vTaskDelay(500); //睡眠500ms
LED0=1;
printf("LED0灭\r\n");
vTaskDelay(500);
}
}
/*LED1周期性闪烁任务*/
void LED1Task(void *pvParameters)
{
while(1)
{
LED1=0;
printf("LED1亮\r\n");
vTaskDelay(1000); //睡眠1000ms
LED1=1;
printf("LED1灭\r\n");
vTaskDelay(1000);
}
}
/*串口周期性发送任务*/
void USARTTask(void *pvParameters)
{
while(1)
{
printf("hello LYJ!!!\r\n");
vTaskDelay(2000); //睡眠2000ms
}
}
/*温湿度周期性采集任务*/
void AHT20Task(void *pvParameters)
{
while(1)
{
/*仅作为框架使用,代码后续添加*/
printf("已采集温湿度\r\n");
vTaskDelay(5000); //睡眠5000ms
}
}
int main(void)
{
delay_init(); //延时函数初始化
uart_init(115200);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
LED_Init(); //初始化与LED连接的硬件接口
//创建LED0任务
xTaskCreate(
LED0Task, //任务函数指针
"LED_TASK1",//任务名称
40, //堆栈深度(字)
NULL, //任务参数为空
1, //任务优先级
NULL //任务句柄为空
);
//创建LED1任务
xTaskCreate(LED1Task,"LED1_TASK2",40,NULL,1,NULL);
//创建串口任务
xTaskCreate(USARTTask,"USART_TASK3",40,NULL,1,NULL);
//创建温湿度采集任务
xTaskCreate(AHT20Task,"AHT20_TASK4",40,NULL,1,NULL);
//启动任务调度器(开始运行操作系统)
vTaskStartScheduler();
while(1)
{
}
}
3.实验结果
从结果可以看出,LED0每500ms亮一次,LED1每1000ms亮一次,串口每2000ms发一次,温湿度每5000ms采集一次。
(四)总结
在这次实验之前,我都用的是裸机编程,但是通过FreeRTOS嵌入式操作系统的移植实验,使我感觉仿佛找到了新大陆。对我来说,使用一个十分小巧的操作系统就能实现多个任务之间的调度运行是一件非常棒的事情,这也让我想去更加深入的了解这一方面的内容。
1.FreeRTOS-百度百科
2.FreeRTOS应用开发笔记之一:FreeRTOS在STM32的移植
3.FreeRTOS移植到STM32上的移植过程
4.freertos移植stm32 步骤分析
5.STM32F1 FreeRTOS开发手册_V1.1