前言
一、FreeRTOS是什么
二、FreeRTOS的移植
1. 资料下载
2. 开始移植
2.1 移植Source源码文件
2.2 添加 FreeRTOSConfig.h
2.3 添加SYSTEM文件夹
2.4 复制 main.c 文件进行测试
前言
裸机开发一段时间,会因为各种需求转而引入操作系统,而FreeRTOS实时操作系统目前与Linux操作系统平分秋色,本篇文章就来初探一下FreeRTOS的面貌,以及实现FreeROTS在STM32上面的移植。
一、FreeRTOS是什么
RTOS 是Real Time Operating System 实时操作系统的简称,在裸机系统中,所有的程序基本都是自己写的,所有的操作都是在一个无限的大循环里面实现。现实生活中的很多中小型的电子产品用的都是裸机系统,而且也能够满足需求。 但随着产品要实现的功能越来越多,单纯的裸机系统已经不能够完美地解决问题,反而会使编程变得更加复杂,如果想降低编程的难度,我们可以考虑引入 RTOS 实现多任务管理,这是使用 RTOS 的最大优势,而国外开源且免费的FreeRTOS是其中市场占有率最高的。
二、FreeRTOS的移植
1. 资料下载
进入FreeRTOS官网,点击右上角的 Download FreeRTOS
FreeRTOS - Market leading RTOS (Real Time Operating System) for embedded systems with Internet of Things extensions
![](https://img-blog.csdnimg.cn/8116e79edc3c45dc82303cce520f0422.png)
目前22年8月上旬的版本是202112.00,版本应该比较稳定了。登陆官网很快,但是下载文件的时候速度很慢,这边给大家提供了从官网下载下来的FreeRTOS文件包。![](https://img-blog.csdnimg.cn/092c4b4585e24f3b9781894ae2b2b709.png)
链接:https://pan.baidu.com/s/1nSGu0u8VSf2m8YitALiDWw
提取码:146v
2. 开始移植
2.1 移植Source源码文件
下载解压文件后打开,进入 FreeRTOSv202112.00\FreeRTOS\ 文件夹就能看到FreeRTOS的源码了,其中
- Demo 文件夹里面就是FreeRTOS的相关例程,里面根据不同的MCU提供了对应的Demo。
- License 文件夹是相关的许可信息。
- Source 文件夹里面的内容就是我们要移植的源码文件。
![](https://img-blog.csdnimg.cn/79e3ee8b3028402d88ea2ff64313e1c1.png)
FreesRTOS是一个系统,那软件就是通过 portable 文件夹里面的东西与硬件去产生链接的,这个文件夹里包括要选择的编译器(Keil、IAR等)以及内存管理(MemMang)、架构的选择(RVDS)。我们在基础工程中新建文件夹名字叫 FreeRTOS ,然后把整个 Source 文件夹里的内容都复制到里面去。
![](https://img-blog.csdnimg.cn/68e051931eb649f2af0a13b02b470077.png)
其中 portable 文件夹我们只需要留下 Keil MemMang RVDS 这三个文件夹,其他的内容都可以删掉。
![](https://img-blog.csdnimg.cn/99478e364d194f19a39487ad4b3dccc6.png)
打开Keil的基础工程,新增两个分组 FreeRTOS_CODE 和 FreeRTOS_PORTTABLE,然后向分组中添加我们刚刚加入 FreeRTOS 文件夹中的文件。
![](https://img-blog.csdnimg.cn/e459215df0ab4876ad1a5ba0268f49c9.png)
![](https://img-blog.csdnimg.cn/0b407fa9bfd44e5d980fcd1de56f02d0.png)
heap_4.c在 MemMang文件夹中, 是FreeRTOS的内存管理文件,总共有5种管理方式,我们这里选择heap_4.c。
port.c是在 RVDS 文件夹下的 ARM_CM3 文件夹中,因为我用的STM32F103是Cortex-M3内核的,FreeRTOS针对不同的MCU都有不同的连接桥梁,这个可以根据自己芯片的内核选择对应文件夹下的port.c文件。
另外需要注意我们有用到的头文件要去添加头文件路径,不然编译找不到的。
2.2 添加 FreeRTOSConfig.h
FreeRTOSConfig.h是FreeRTOS的配置文件,里面有各种宏定义来对于操作系统的功能进行裁剪、配置。这个文件在我们从官方下的源码的 Demo 文件中,根据芯片选择对应的文件夹,这边是针对STM32F103的移植,所以选择 CORTEX_STM32F103_Keil 文件夹。
![](https://img-blog.csdnimg.cn/04290b79a96049eab159621b071c1159.png)
2.3 添加SYSTEM文件夹
在基础工程下,新建 SYSTEM 文件夹,然后将配置好的 delay sys usart 文件夹复制过来。
![](https://img-blog.csdnimg.cn/751d22f1e27a4a4e9597a1c6c3514600.png)
![](https://img-blog.csdnimg.cn/4b06b027c16c435b91cb4452d9fc53fc.png)
这样加上我们之前添加的文件,我们要添加的文件路径有以下这些。只要有用到的.h文件的路径我们都要添加进来。
![](https://img-blog.csdnimg.cn/66e37285864448aa818371becd505073.png)
然后编译,
如果出现 …\FreeRTOS\queue.c(2762): error: #268: declaration may not appear after executable statement in block 的问题,在Keil的魔术棒中C/C++选项卡下选择C99mode即可。
然后系统会提示出现三个 error 信号:
![](https://img-blog.csdnimg.cn/c814195c4f35471e9f0f6f0549f8eaa5.png)
这时我们到中断文件stm32f10x_it.c中将这三个函数屏蔽掉即可。
2.4 复制 main.c 文件进行测试
首先我们添加点灯文件 Led.h 与 Led.c ,同样记得把 .h 文件的路径添加到工程中。
然后将下面的代码复制到 main.c 中进行测试
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED0_TASK_PRIO 2
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 3
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建LED0任务
xTaskCreate((TaskFunction_t )led0_task,
(const char* )"led0_task",
(uint16_t )LED0_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED0_TASK_PRIO,
(TaskHandle_t* )&LED0Task_Handler);
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED0任务函数
void led0_task(void *pvParameters)
{
while(1)
{
LED0=~LED0;
vTaskDelay(500);
}
}
//LED1任务函数
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)