嵌入式哞哞哥FreeRTOS系统移植视频教程

xiao_wenwen123 · · 46 次点击 · · 开始浏览    

嵌入式哞哞哥FreeRTOS系统移植视频教程

嵌入式哞哞哥带你吃透 FreeRTOS 移植:从原理到 STM32 实战

“下仔客”: itxt.top/17049/

在嵌入式开发圈,FreeRTOS 凭借轻量、可裁剪、实时性强的特性,成为单片机项目从 "裸机循环" 升级到 "多任务系统" 的首选。但对新手而言,"系统移植" 四个字总带着神秘色彩 ——"底层硬件千差万别,怎么让通用内核适配我的芯片?"" 汇编代码看不懂,是不是学不会移植?"

别急!擅长把复杂技术讲通俗的嵌入式哞哞哥,今天就用 "草原牛进钟表厂" 的比喻,带你从零吃透 FreeRTOS 移植。就像让习惯自由奔跑的牛适配精密工厂的作息,移植本质就是给 FreeRTOS 内核定制一套 "硬件适配手册",哪怕你刚懂 STM32 基础操作,跟着步骤走也能成功让内核在芯片上 "安家落户"。

一、哞哞哥的灵魂三问:先搞懂移植的核心逻辑

动手前先理清三个关键问题,避免盲目堆砌代码 —— 这可是哞哞哥强调的 "先懂原理再动手" 原则:

1. 什么是 FreeRTOS 移植?为啥需要移植?

FreeRTOS 内核本身是用标准 C 语言写的 "通用管理系统",就像一套通用的工厂管理制度,但不同芯片(STM32、ESP32、NXP)的 "硬件车间" 差异巨大:

  • 有的芯片堆栈从高地址往低地址长(如 ARM Cortex-M 系列),有的正好相反;
  • 中断控制、寄存器操作的指令各不相同;
  • 编译器(Keil、IAR、GCC)对汇编代码的支持也有差异。

移植就是给这套通用制度加个 "硬件适配层",让 FreeRTOS 能看懂目标芯片的 "方言",知道怎么切换任务、怎么控制中断、怎么管理内存。简单说:移植 = 通用内核 + 硬件适配层,其中适配层才是移植的核心,占比不到 10% 的代码量。

2. 移植只需要改两个文件?真的假的?

真的!哞哞哥敲黑板:FreeRTOS 的代码结构极清晰,90% 以上的内核代码(tasks.c、queue.c 等)完全通用,移植只需要聚焦两个关键文件:

  • portmacro.h:用宏定义适配硬件特性,比如堆栈增长方向、中断屏蔽指令;
  • port.c:实现硬件相关的函数,核心是任务上下文切换、系统时钟初始化等。

这就像给牛定制装备:portmacro.h 是 "尺寸表"(告诉内核硬件的基本参数),port.c 是 "操作手册"(告诉内核怎么控制硬件)。其他文件直接复用,根本不用动!

3. 零基础学移植,需要哪些前置知识?

别被 "底层开发" 吓到,哞哞哥说只要掌握 3 样基础就能入门:

  • 芯片基础:知道 STM32 的 NVIC(中断控制器)、SysTick(系统滴答定时器)基本概念;
  • C 语言基础:能看懂函数指针、宏定义,了解条件编译;
  • 工具使用:会用 Keil MDK 创建 STM32 工程,能烧录程序看 LED 灯闪烁。

至于汇编?完全不用怕!移植用的汇编代码就几行固定模板,背下来直接用,哞哥会把每句的意思讲明白。

二、移植前的准备:哞哞哥的 "工具清单"

就像干活前先备齐工具,移植前要准备 3 样东西,10 分钟就能搞定:

1. 核心 "原材料":FreeRTOS 源码

去 FreeRTOS 官网下载最新版源码,解压后重点看这几个文件夹:

  • Source:内核核心代码,包含 tasks.c(任务管理)、queue.c(队列)等通用文件;
  • Source/portable:移植模板文件夹,里面有不同编译器、芯片的适配示例(比如 GCC/ARM_CM4F 对应 Cortex-M4 内核);
  • Source/portable/MemMang:内存管理文件,新手直接用 heap_4.c(支持动态内存分配和释放)。

2. 目标 "工作台":STM32 基础工程

先创建一个能让 LED 闪烁的 STM32 裸机工程(以 STM32F103C8T6 为例),确保:

  • 时钟配置正确(比如 72MHz);
  • 至少有一个 LED 引脚配置为推挽输出;
  • 能正常编译、烧录、运行。

这就像先把钟表厂的车间打扫干净,确保基础设备能正常运转。

3. 适配 "参考图":芯片手册关键页

翻出 STM32F103 的参考手册,重点标记两个部分:

  • NVIC 中断控制器:查看 SysTick 中断的优先级配置方法;
  • SysTick 定时器:了解怎么配置定时器周期、开启中断。

不用通读手册,哞哥说这两处就像 "安装说明书" 的关键步骤,用到再看。

三、实战移植:跟着哞哞哥改 5 步,内核跑起来

以 "STM32F103C8T6 + Keil MDK" 为例,跟着哞哥的步骤一步步改,30 分钟完成移植:

第 1 步:把 FreeRTOS 源码 "搬进" 工程

  1. 在裸机工程里新建 "FreeRTOS" 文件夹,再建 3 个子文件夹:
    • Source:复制源码 Source 文件夹下的所有.c 文件(除了 example 文件夹);
    • Include:复制源码 Source/include 文件夹下的所有.h 文件;
    • Portable:复制 Source/portable/Keil/ARM_CM3 文件夹(对应 Cortex-M3 内核)和 Source/portable/MemMang/heap_4.c。
  1. 在 Keil 中添加文件到工程,分 3 个组:
    • FreeRTOS_Core:添加 Source 文件夹下的 tasks.c、queue.c、list.c;
    • FreeRTOS_Portable:添加 Portable 文件夹下的 port.c 和 heap_4.c;
    • FreeRTOS_Include:把 Include 和 ARM_CM3 文件夹添加到工程包含路径。

第 2 步:改配置文件:FreeRTOSConfig.h

这是移植的 "总开关",新建一个 FreeRTOSConfig.h 文件放到工程里,关键配置哞哥已经帮你写好,新手只需改这几处:


 

#ifndef FREERTOS_CONFIG_H

#define FREERTOS_CONFIG_H

// 1. 时钟配置:STM32主频72MHz,所以这里填72000000

#define configCPU_CLOCK_HZ (72000000UL)

// 2. 系统滴答定时器频率:1000Hz(每1ms触发一次中断)

#define configTICK_RATE_HZ (1000UL)

// 3. 任务栈大小:单位是字(4字节),这里设128字=512字节

#define configMINIMAL_STACK_SIZE (128UL)

// 4. 最大任务数:最多创建4个任务

#define configMAX_TASK_NAME_LEN (16)

#define configMAX_PRIORITIES (4UL)

// 5. 启用动态内存分配(因为用了heap_4.c)

#define configSUPPORT_DYNAMIC_ALLOCATION (1)

// 6. 中断相关配置:适配Cortex-M3

#define configPRIO_BITS (4UL)

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

// 启用必要的API函数

#define INCLUDE_vTaskStartScheduler 1

#define INCLUDE_vTaskDelay 1

#define INCLUDE_xTaskCreate 1

#endif /* FREERTOS_CONFIG_H */

第 3 步:改 portmacro.h:告诉内核硬件 "尺寸"

这个文件在 ARM_CM3 文件夹下,新手基本不用改,重点理解这两个宏:


 

// 堆栈增长方向:Cortex-M系列堆栈从高地址往低地址长,所以设为-1

#define portSTACK_GROWTH ( -1 )

// 任务切换中断号:用PendSV中断(专门用于任务切换,优先级最低)

#define portNVIC_PENDSV_IRQ_NUMBER 14

哞哥说:这就像告诉牛 "车间的门在左边,走路要靠右侧",是硬件的基本规矩。

第 4 步:改启动文件:让内核接管中断

打开 STM32 的启动文件(startup_stm32f10x_md.s),找到这两处修改:

  1. 注释掉原来的 SysTick 中断服务函数

 

; SysTick_Handler:

; B SysTick_Handler

  1. 保留 PendSV 和 SysTick 的中断向量:这两个中断是 FreeRTOS 的 "核心指令",PendSV 负责任务切换,SysTick 负责系统时钟。

为啥要注释?因为 FreeRTOS 的 port.c 里已经实现了这两个中断的处理函数,再留着裸机的会冲突。

第 5 步:写测试代码:让 LED"多任务" 闪烁

移植对不对,跑个多任务测试就知道。在 main.c 里写两个任务:一个 LED1 每隔 500ms 闪烁,一个 LED2 每隔 1000ms 闪烁:


 

#include "stm32f10x.h"

#include "FreeRTOS.h"

#include "task.h"

// 初始化LED引脚

void LED_Init(void) {

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitTypeDef GPIO_InitStruct;

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStruct);

}

// 任务1:LED1闪烁(PA0)

void Task1_Func(void *pvParameters) {

while(1) {

GPIO_SetBits(GPIOA, GPIO_Pin_0);

vTaskDelay(500); // 延时500ms(FreeRTOS的延时函数,会释放CPU)

GPIO_ResetBits(GPIOA, GPIO_Pin_0);

vTaskDelay(500);

}

}

// 任务2:LED2闪烁(PA1)

void Task2_Func(void *pvParameters) {

while(1) {

GPIO_SetBits(GPIOA, GPIO_Pin_1);

vTaskDelay(1000); // 延时1000ms

GPIO_ResetBits(GPIOA, GPIO_Pin_1);

vTaskDelay(1000);

}

}

int main(void) {

LED_Init();

// 创建两个任务

xTaskCreate(Task1_Func, "Task1", 128, NULL, 1, NULL);

xTaskCreate(Task2_Func, "Task2", 128, NULL, 1, NULL);

// 启动任务调度器(FreeRTOS开始工作)

vTaskStartScheduler();

// 只要调度器启动成功,下面的代码永远不会执行

while(1);

}

编译、烧录后,如果看到两个 LED 按不同频率闪烁,说明移植成功了!这时候 FreeRTOS 已经在后台自动切换两个任务,比裸机的 "循环延时" 优雅 100 倍。

四、哞哞哥的排坑指南:新手最容易踩的 3 个坑

移植时遇到问题别慌,哞哥总结了新手最常踩的 3 个坑,对照排查准能解决:

1. 编译报错 "找不到 FreeRTOSConfig.h"

原因:工程包含路径没加对。

解决:在 Keil 的 "Options for Target"→"C/C++"→"Include Paths" 里,把 FreeRTOS 的 Include 和 ARM_CM3 文件夹路径加上,记得用绝对路径或相对路径(如 "../FreeRTOS/Include")。

2. 程序跑飞,LED 不亮

原因 1:启动文件的 SysTick 中断没注释。FreeRTOS 和裸机的中断服务函数冲突了,注释掉裸机的即可。

原因 2:内存分配问题。heap_4.c 没加进工程,或者 configSUPPORT_DYNAMIC_ALLOCATION 没设为 1,导致任务创建失败。

3. 任务延时没效果,LED 常亮

原因:vTaskDelay () 函数没启用。在 FreeRTOSConfig.h 里把 INCLUDE_vTaskDelay 设为 1,确保调度器能正常切换任务。

哞哥提醒:遇到编译错误先看报错信息的 "文件" 和 "行号",90% 的问题都出在配置文件或路径上,别一上来就怀疑自己的移植能力。

五、进阶思考:移植的本质是 "硬件抽象"

成功移植后,哞哥建议多想一步:FreeRTOS 为啥能跨这么多芯片?核心是 "硬件抽象层(HAL)" 的设计思想 —— 把硬件相关的操作全部封装在 port.c 和 portmacro.h 里,内核完全不碰硬件细节。

就像钟表厂的管理制度(内核)不变,但给不同设备(芯片)配不同的操作手册(移植层),就能让制度在任何设备上运行。理解这一点,以后移植到 ESP32、NXP 芯片也能举一反三:无非是换一套 port 文件,改改配置里的时钟和中断参数。

六、哞哞哥的学习资源推荐

想深入学习?哞哥推荐 3 个免费资源,都是嵌入式圈的 "宝藏":

  1. 官方文档:FreeRTOS 官网的 "Porting Guide",最权威的移植原理说明,虽然是英文但词汇简单,配合翻译工具能看懂;
  1. 视频教程:B 站 "嵌入式哞哞哥" 的 FreeRTOS 系列,有手把手移植的实操演示,连 Keil 配置都讲得明明白白;
  1. 实战案例:GitHub 搜索 "FreeRTOS-STM32-Demo",找 STM32F103 的移植示例,对比自己的代码找差异。

七、结语:移植不是终点,是多任务开发的起点

跟着哞哥做完移植,你会发现:FreeRTOS 移植根本不是什么高深技术,无非是 "配配置、改文件、做测试" 的标准化流程。就像让草原牛适应了钟表厂的作息,接下来就能让它高效完成多任务工作 —— 比如同时处理传感器采集、数据传输、OLED 显示,这才是 RTOS 的真正价值。

嵌入式开发的魅力就在于此:从控制一个 LED,到管理一个复杂系统,每一次技术升级都能带来质的飞跃。现在你已经掌握了 FreeRTOS 移植的核心方法,接下来不妨试试添加队列、信号量,实现任务间的通信,开启你的多任务开发之旅吧!


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

46 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传