✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
一、引言
FreeRTOS 是一个开源的、轻量级的实时操作系统内核,广泛应用于嵌入式系统开发中。STM32 系列微控制器以其高性能、低功耗和丰富的外设资源而受到开发者的青睐。将 FreeRTOS 移植到 STM32 上,可以充分发挥 STM32 的性能,实现多任务处理,提高系统的可靠性和可维护性。本文将详细介绍如何将 FreeRTOS 移植到 STM32 上,并给出相应的代码示例。
二、移植前的准备工作
2.1 硬件平台
选择一款合适的 STM32 开发板,本文以 STM32F103C8T6 为例。
2.2 软件工具
- Keil MDK:用于编写、编译和调试代码。
- FreeRTOS 源码:可以从 FreeRTOS 官方网站(https://www.freertos.org/)下载最新版本的源码。
三、移植步骤
3.1 下载并解压 FreeRTOS 源码
将下载的 FreeRTOS 源码解压到本地,其中与移植相关的主要文件夹有:
FreeRTOS\Source
:包含 FreeRTOS 内核的源文件。FreeRTOS\Source\portable
:包含不同平台的移植文件。
3.2 创建 Keil 工程
在 Keil MDK 中创建一个新的 STM32 工程,选择对应的芯片型号(如 STM32F103C8T6)。
3.3 添加 FreeRTOS 源码到工程
- 复制文件:将
FreeRTOS\Source
文件夹下的所有.c
文件复制到工程目录下的FreeRTOS\Source
文件夹中。 - 添加到工程:在 Keil 工程中添加这些
.c
文件到相应的分组中。
3.4 选择移植文件
在 FreeRTOS\Source\portable
文件夹中,选择适合 STM32 的移植文件:
- 对于 ARM Cortex-M3 内核的 STM32F103 系列,选择
RVDS\ARM_CM3
文件夹。将该文件夹下的port.c
和portmacro.h
文件复制到工程目录下的FreeRTOS\Source\portable
文件夹中,并添加到工程中。 - 复制
MemMang
文件夹下的heap_4.c
文件到工程目录下的FreeRTOS\Source\portable
文件夹中,并添加到工程中。heap_4.c
是 FreeRTOS 的内存管理文件。
3.5 配置 FreeRTOS 头文件
将 FreeRTOS\Source\include
文件夹下的所有 .h
文件复制到工程目录下的 FreeRTOS\include
文件夹中。同时,将 FreeRTOS\Source\portable\RVDS\ARM_CM3
文件夹下的 portmacro.h
文件复制到 FreeRTOS\include
文件夹中。
3.6 创建 FreeRTOS 配置文件
在工程目录下创建 FreeRTOSConfig.h
文件,该文件用于配置 FreeRTOS 的参数。以下是一个简单的 FreeRTOSConfig.h
示例:
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#include "stm32f10x.h"
/* 定义内核时钟频率 */
#define configCPU_CLOCK_HZ (SystemCoreClock)
/* 定义滴答定时器频率 */
#define configTICK_RATE_HZ ((TickType_t)1000)
/* 定义最大任务优先级 */
#define configMAX_PRIORITIES (5)
/* 定义空闲任务栈大小 */
#define configMINIMAL_STACK_SIZE ((unsigned short)128)
/* 定义堆大小 */
#define configTOTAL_HEAP_SIZE ((size_t)(10 * 1024))
/* 使能抢占式调度器 */
#define configUSE_PREEMPTION 1
/* 使能时间片调度 */
#define configUSE_TIME_SLICING 1
/* 使能空闲任务钩子函数 */
#define configUSE_IDLE_HOOK 0
/* 使能滴答定时器钩子函数 */
#define configUSE_TICK_HOOK 0
/* 定义中断优先级分组 */
#define configKERNEL_INTERRUPT_PRIORITY ((UBaseType_t)configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ((UBaseType_t)configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
/* 定义中断优先级位数 */
#define configPRIO_BITS 4
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x05
#endif /* FREERTOS_CONFIG_H */
3.7 修改系统时钟和滴答定时器配置
在 stm32f10x_it.c
文件中,修改 SysTick_Handler
函数为:
extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{
#if (INCLUDE_xTaskGetSchedulerState == 1 )
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
#endif /* INCLUDE_xTaskGetSchedulerState */
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
}
#endif /* INCLUDE_xTaskGetSchedulerState */
}
同时,在 main.c
文件中配置系统时钟和滴答定时器:
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
// 任务句柄
TaskHandle_t Task1Handle = NULL;
// 任务 1 函数
void Task1(void *pvParameters)
{
while (1)
{
// 任务 1 的代码
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void)
{
// 配置系统时钟
SystemInit();
// 配置滴答定时器
if (SysTick_Config(SystemCoreClock / configTICK_RATE_HZ))
{
while (1);
}
// 创建任务
xTaskCreate(Task1, "Task1", 128, NULL, 1, &Task1Handle);
// 启动调度器
vTaskStartScheduler();
// 如果调度器启动失败,程序会执行到这里
while (1);
}
四、代码解释
4.1 FreeRTOSConfig.h
文件
该文件用于配置 FreeRTOS 的各种参数,如内核时钟频率、滴答定时器频率、任务优先级、堆大小等。开发者可以根据实际需求进行调整。
4.2 SysTick_Handler
函数
该函数是滴答定时器的中断处理函数,在该函数中调用 xPortSysTickHandler()
函数,用于更新 FreeRTOS 的系统时钟。
4.3 main.c
文件
SystemInit()
:配置系统时钟。SysTick_Config()
:配置滴答定时器的中断周期。xTaskCreate()
:创建一个新的任务,指定任务函数、任务名称、任务栈大小、任务参数、任务优先级和任务句柄。vTaskStartScheduler()
:启动 FreeRTOS 调度器,开始任务调度。
五、编译和调试
完成上述步骤后,编译 Keil 工程。如果编译过程中出现错误,根据错误信息进行排查和修正。编译成功后,将生成的二进制文件下载到 STM32 开发板上进行调试。
六、注意事项
- 内存管理:根据实际需求选择合适的内存管理文件(如
heap_4.c
),并合理配置堆大小。 - 中断优先级:确保 FreeRTOS 的中断优先级与 STM32 的中断优先级分组相匹配,避免中断冲突。
- 任务栈大小:根据任务的复杂度和需求,合理配置任务栈大小,避免栈溢出。
通过以上步骤,我们可以成功将 FreeRTOS 移植到 STM32 上,并实现简单的多任务处理。