一、获取FreeRTOS源码
(1)登录FreeRTOS官网:www.freertos.org,下载第一个压缩包
(2)通过GitHub网站:github.com/FreeRTOS/FreeRTOS下载,由于该网站服务器在国外,所以访问较慢,甚至访问失败,不建议使用
(3)通过网盘资源下载
下载完成后,解压文件后如下图所示:
我们重点关注第一个文件夹:FreeRTOS
Demo:不同系列开发板的示例
Source:源文件
二、FreeRTOS移植
(1)在工程中建立“FreeRTOS”文件夹,同时在该文件夹中建立3个子文件夹:include、source、port
include文件夹用来存放头文件
source文件夹用来存放源码
port文件夹用来存放与内核连接的相关文件
(2)将源码移植到新建文件夹中
FreeRTOSv202212.01\FreeRTOSv202212.01\FreeRTOS\Source路径下的源文件移植到新建的source文件夹中
FreeRTOSv202212.01\FreeRTOSv202212.01\FreeRTOS\Source\include路径下的头文件移植到新建的include文件夹中
FreeRTOSv202212.01\FreeRTOSv202212.01\FreeRTOS\Source\portable\RVDS\ARM_CM3路径下的文件和FreeRTOSv202212.01\FreeRTOSv202212.01\FreeRTOS\Source\portable\MemMang移植到port文件夹中
在FreeRTOS文件夹中的demo文件夹中找到CORTEX_STM32F103_Keil文件夹,复制里面的FreerRTOSConfig.h文件到新建的FreeRTOS文件夹中
(3)打开Keil5,点击魔术棒,选择C/C++,将新移植的头文件路径添加进来
(4)新建组将文件全部添加到工程中,点击魔术棒旁边的三个格子的图标,选择新建组,我们分别新建FreeRTOS_include、FreeRTOS_source、FreeRTOS_port三个组,将工程文件夹source中的所有.c文件添加到FreeRTOS_source中,将工程文件夹include中的所有.h文件添加到FreeRTOS_include中(不包括.readme),将工程文件夹port中的文件(heap_4.c、port.c添加到FreeRTOS_port中,还有配置文件FreeRTOSConfig.h添加到FreeRTOS_include组中
(5)在FreeRTOSConfig.h添加,添加中断函数的宏定义
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
这两个宏定义: PendSV_Handler——用于出发任务切换操作,SysTick_Handler——用于实现定时功能,SVC_Handler——用于实现系统用调用三个中断函数,当运行之后,会出现函数重定义错误,因为在stm32f10x_it.c文件中已经包含了这三个函数,需要进行删掉
(6)完善systick中断服务函数
上面定义的两个宏直接使用的port.c自带的函数。但systick中断服务函数功能还没有完善,具体代码如下。就是在stm32f10x_it.c文件中的函数里修改即可
extern void xPortSysTickHandler(void);
//systick中断服务函数
void SysTick_Handler(void)
{
#if (INCLUDE_xTaskGetSchedulerState == 1 )
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
#endif /* INCLUDE_xTaskGetSchedulerState */
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
}
#endif /* INCLUDE_xTaskGetSchedulerState */
}
至此,FreeRTOS已经成功移植到STM32F103C8T6
三、测试程序
3.1 首先在main文件中添加头文件FreeRTOS.h和task.h
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "FreeRTOS.h"
#include "task.h"
3.2 创建任务函数
TaskHandle_t task1Handler; //任务句柄
static void task1(void *arg) //任务函数
{
while(1)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
vTaskDelay(500);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
vTaskDelay(500);
}
}
3.3 在主函数中创建任务,并开启任务调度器
xTaskCreate(task1,"task1",512,NULL,2,&task1Handler);
vTaskStartScheduler(); //开启调度器
3.4 初始化GPIO口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //打开GPIOC的时钟
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 ;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct); //初始化C13
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t task1Handler; //任务句柄
static void task1(void *arg) //任务函数
{
while(1)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
vTaskDelay(500);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
vTaskDelay(500);
}
}
int main()
{
//uint8_t i = 0;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //打开GPIOC的时钟
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 ;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct); //初始化C13
xTaskCreate(task1,"task1",512,NULL,2,&task1Handler);
vTaskStartScheduler(); //开启调度器
while(1)
{
}
}
如果LED以500ms进行闪烁,则证明FreeRTOS移植成功