尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
【Stm32f1实时操作系统移植】FreeRTOS移植实战,保姆级小白教程
文章目录O、说在前面的话一、名词解释简单版1.裸机2.操作系统(RTOS)二、移植流程1.使用keil工具新建工程2.规范工程文件夹并拷贝文件3.Keil工具配置三、运行测试代码解决方法1.注释原中断函数重映射到操作系统的中断函数解决方法2.修改向量表直接使用FreeRTOS的中断函数其他参考资料/博客/文章O、说在前面的话之前的移植流程都忘记差不多了尽量留存博客笔记确实可以方便自己回忆。平台keil5-MDK、Win11电脑、STM32F103C8T6最小系统板开发环境未配置的可以去看keil5安装的博客一、名词解释简单版1.裸机什么是裸机裸机是指没有操作系统的单片机程序。程序直接在硬件上运行所有代码都在一个 main 函数的大循环Super Loop中执行如下代码块所示。intmain(void){/* 初始化 */SystemInit();GPIO_Init();USART_Init();Timer_Init();/* 超级循环 */while(1){Key_Scan();// 扫描按键LED_Process();// 处理LEDUART_Process();// 处理串口数据Sensor_Read();// 读取传感器delay_ms(10);// 延时}}裸机的特点简单直接代码逻辑清晰容易理解和调试资源占用极少几乎没有额外开销适合资源受限的MCU如51、AVR实时性不可控如果一个函数执行时间过长其他任务就会被阻塞任务间耦合度高所有功能在一个循环里牵一发而动全身不适合复杂系统当任务数超过5~8个时代码会变得难以维护裸机的适用场景非常简单的小项目如单LED闪烁、按键控制资源极度受限的芯片如1KB RAM以下的MCU对实时性要求不高、任务少的场合2.操作系统(RTOS)什么是RTOSRTOSReal-Time Operating System是一种能够保证任务在确定时间内完成的操作系统。它不是Linux那种“分时系统”而是“实时系统”——任务的响应时间是可预测的。RTOS的核心概念概念说明类别任务Task独立的执行单元每个任务有自己的栈和优先级就像公司里的不同部门调度器Scheduler决定哪个任务在什么时候运行像项目经理安排工作优先级Priority任务的紧急程度数字越大优先级越高像VIP客户优先服务延时Delay任务主动放弃CPU进入休眠像员工请假休息阻塞Block任务等待某个条件如队列、信号量像等电梯上下文切换保存当前任务状态切换到另一个任务像切换工作台RTOS的典型结构voidLedTask(void*pvParameters){for(;;){LED_Toggle();vTaskDelay(500);// 主动让出CPU500ms后再回来}}voidUartTask(void*pvParameters){for(;;){xQueueReceive(uart_queue,data,portMAX_DELAY);// 阻塞等待数据Process_Data(data);}}intmain(void){xTaskCreate(LedTask,LED,128,NULL,2,NULL);xTaskCreate(UartTask,UART,256,NULL,1,NULL);vTaskStartScheduler();while(1);}RTOS的特点任务独立每个任务写成一个函数互不干扰实时性强高优先级任务能在确定时间内得到响应资源开销适中通常需要2~10KB RAM几百字节到几KB Flash调试相对复杂需要理解任务调度、优先级反转等概念适合复杂系统当任务超过5个时RTOS的优势明显RTOS的适用场景多个任务需要“同时”运行的场景有严格时间要求的控制系统如无人机、机器人通信协议栈较多的物联网设备需要模块化开发的团队项目参考链接: 完整教程STM32之FreeRTOS移植重点二、移植流程为方便小白理解从新建工程开始移植FreeRTOS实时操作系统。1.使用keil工具新建工程如图2.1.1所示打开Keil点击project选择 new project 新建工程。图2.1.1选择完工程文件保存位置和工程名后如图2.1.2选择使用的芯片我这里用的是F103c8t6。图2.1.2如图2.1.3是创建完成Keil工具界面2.1.4是新建工程自动生成工程文件夹的结构。图 2.1.3图 2.1.42.规范工程文件夹并拷贝文件文件夹结构这样不够完整和清晰我们修改下文件夹结构新建文件夹并规范化命名如图2.2.1。图 2.2.1*这里面多出的**keilkilll.bat**也是新增进来的用于清理编译生成的文件的可执行脚本编译生成的文件会占用很大的储存空间此脚本可用于工程完成后清理空间或在压缩传输工程前减小体积便于发送一般写工程都会塞一个进来*这里再对自然生成的和手动添加的文件夹做个统一介绍文件名描述CORE内核文件STARTUP根据主控芯片容量选择的启动文件 startup_stm32f10x_md.sLibrary标准库函数System串口usart、延时函数等文件BSP板级外设驱动文件如板载LED、软件IIC、SPI驱动板子简单可和Hardware合并不细分Hardware外设驱动文件OLED、LED、蜂鸣器、传感器等外设FreeRTOSFreeRTOS核心文件DebugConfig存放调试配置缓存。每次进入调试模式Debug时Keil 会生成临时的调试脚本或配置Listings存放编译列表文件。包括 .lst 汇编列表、.map 内存映射文件。排查 FreeRTOS 的 HardFault、看内存占用时这里的 .map 文件非常有用Object存放最终编译产物。包括 .o 目标文件、.axf 可执行文件调试用、.hex / .bin烧录固件最终烧录到 STM32 的文件就在这里文件夹创建好之后拷贝文件到文件夹有变动的文件夹文件如下。①.CORE:图 2.2.2②.STARTUP:图 2.2.3这里我保留了全部.s文件实际上只需要用到主控芯片对应的一个.s文件就可以了都保留的话移植到其他同系列不同规格芯片的时候在keil里修改这个文件夹里添加的.s文件即可。如果想要极致压缩工程大小可以只保留需要的.s文件。③.Library:图 2.2.4标准库函数全部拷贝过来即可④.System:图 2.2.5一点简易的串口和延时函数⑤.User:图 2.2.6⑥.FreeRTOS:这里着重介绍这个文件夹也就是FreeRTOS核心文件的移植和配置。解压完官方文件如图2.2.7。图 2.2.7如图2.2.8点击官方文件FreeRTOS-Source这里面的include文件夹直接拷贝到我们工程下的FreeRTOS文件夹。同时绿框的3个.c文件list.c、queue.c、tasks.c文件也需要拷贝。图 2.2.8随后还需要官方portable文件夹中的文件需要根据开发环境编译器相关文件选择。如图2.2.9我们找到 FreeRTOS-Source-portable中的keil文件夹里面提示我们看RVDS文件夹在RVDS文件夹中找到主控芯片对应的文件也就是ARM_CM3文件夹拷贝里面的文件port.c、portmacro.h到工程的portable文件夹中。图 2.2.9此外还需要官方portable中MemMang文件夹的一个内存管理实现.c文件我们直接选择其中的heap_4.c文件拷贝。最后得到图2.2.10所示内容。图 2.2.10到这里还不够我后来编译发现报错缺少一个FreeRTOSConfig.h头文件。我们在官方文件夹中找到demo例程如图2.2.11找到对应芯片和开发工具的文件夹在里面找到FreeRTOSConfig.h文件拷贝到自己工程的FreeRTOS文件夹下。图 2.2.11最终工程的FreeRTOS文件夹文件内容如图2.2.12所示。FreeRTOS图 2.2.12二级子目录include图 2.2.12二级子目录portable图 2.2.12完成上述文件拷贝整理流程后接下来到keil工具内配置好一切相关设置。3.Keil工具配置工具配置如果配置的有问题也会导致移植报错、编译报错等问题所以我还是贴出了较为详细的流程熟练工具使用的可以自行跳过如图2.3.1打开keil点击蓝框的管理项目工程文件工具然后在弹出的窗口点击绿框按钮新建、修改分支名称并点击黄框按钮在对应的分支项目内添加对应的文件这里项目名称和文件夹的名称命名一样方便查找和管理。最终红框将全部.c文件、部分.h文件添加到工程项目内。图 2.3.1如图2.3.2红框是已经配置好的工程项目结构。随后选择绿框的魔法棒工具在弹出的Target窗口ARM Compiler选择version 5。图 2.3.2如图2.3.3在绿框c/c选项窗口界面Define输入USE_STDPERIPH_DRIVER宏定义然后点include Paths右侧三点给工程添加头文件路径添加结果如图2.3.4所示。图 2.3.3图 2.3.4自此工具配置完成。找AI随便生成一个main函数创建两个任务一个定时点灭板载LED灯另外一个任务发送数据。如图2.3.5所示编译无报错。图 2.3.5#includeFreeRTOS.h#includetask.h#includequeue.h#includestm32f10x.h/* 任务句柄 */TaskHandle_t led_task_handleNULL;TaskHandle_t print_task_handleNULL;/* 队列句柄 */QueueHandle_t msg_queueNULL;/* 前向声明 */voidLedTask(void*pvParameters);voidPrintTask(void*pvParameters);intmain(void){NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);// 4位抢占优先级0位子优先级/* 硬件初始化 */GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);GPIO_InitStructure.GPIO_PinGPIO_Pin_13;GPIO_InitStructure.GPIO_ModeGPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(GPIOC,GPIO_InitStructure);/* 创建队列能存 5 个整数 */msg_queuexQueueCreate(5,sizeof(uint32_t));/* 创建任务 */xTaskCreate(LedTask,LED,128,NULL,2,led_task_handle);xTaskCreate(PrintTask,PRINT,256,NULL,1,print_task_handle);/* 启动调度器 */vTaskStartScheduler();/* 永远不会到这里 */while(1);}/* 任务1LED 闪烁每秒发送一个消息到队列 */voidLedTask(void*pvParameters){uint32_tcount0;for(;;){/* 翻转 LED */GPIOC-ODR^GPIO_Pin_13;/* 发送计数值到队列 */count;xQueueSend(msg_queue,count,0);/* 延时 500ms */vTaskDelay(pdMS_TO_TICKS(1000));}}/* 任务2从队列接收消息并打印 */voidPrintTask(void*pvParameters){uint32_treceived_value;for(;;){/* 等待队列消息无限等待 */if(xQueueReceive(msg_queue,received_value,portMAX_DELAY)pdTRUE){/* 收到消息后模拟打印这里用翻转另一个引脚代替 *//* 在实际项目中这里可以是串口输出 *//* 做一个短延时模拟处理时间 */vTaskDelay(pdMS_TO_TICKS(100));}}}三、运行测试代码编译无报错随后通过烧录器下载程序到板子发现LED灯并没有如代码预期实现的定时闪烁我们进入Debug定位下什么原因。如图3.1.1程序从main函数开始没问题图 3.1.1.如图3.1.2点击红框继续运行后再点击绿框停止运行程序发现程序卡死在void HardFault_Handler(void)故障中断死循环中所以没有执行后面的程序了这是移植FreeRTOS操作系统过程中会遇到的一个经典问题。图 3.1.2问题原因分析核心问题两个“同名”的函数抢着干活我们把问题简化一下FreeRTOS​ 提供了三个核心函数它们负责任务的切换和系统心跳vPortSVCHandler启动第一个任务xPortPendSVHandler执行任务切换xPortSysTickHandler提供系统时钟节拍ST官方启动文件​ 里为这三个异常定义了“弱”入口名字分别是SVC_Handler、PendSV_Handler、SysTick_Handlerstm32f10x_it.c​ 文件里你或者库重新定义了这三个函数即使函数内容是空的。当异常发生时MCU会去哪里它会去向量表里找对应的函数名。向量表里写的是SVC_Handler这个名字。现在编译器面临一个选择链接器找到了 SVC_Handler在 stm32f10x_it.c 里是个空函数链接器也找到了 vPortSVCHandler在 FreeRTOS 的 port.c 里是真正的实现但问题是向量表里只写了 SVC_Handler它不认识 vPortSVCHandler。所以当第一个任务要启动时CPU跳转到 SVC_Handler结果发现那里是个空函数或者一个 while(1)系统立刻就进入死循环了HardFault。解决方法1.注释原中断函数重映射到操作系统的中断函数注释掉原函数并在FreeRTOSConfig.h中增加映射定义。1如图3.1.3在stm32f10x_it.c中注释掉红框的三个函数SVC_Handler、PendSV_Handler、SysTick_Handler图 3.1.32如图3.1.4在FreeRTOSConfig.h中末尾新增下列宏定义。#definevPortSVCHandlerSVC_Handler#definexPortPendSVHandlerPendSV_Handler#definexPortSysTickHandlerSysTick_Handler图 3.1.4此时编译完烧录就可以发现LED灯闪烁程序正常运行了。解决方法2.修改向量表直接使用FreeRTOS的中断函数如图3.1.5在蓝框startup_stm32f10x_md.s向量表中找到红框参照黄色字体SVC_Handler、PendSV_Handler、SysTick_Handler三个函数图 3.1.5将 DCD SVC_Handler DCD PendSV_Handler DCD SysTick_Handler 修改为 DCD vPortSVCHandler DCD xPortPendSVHandler DCD xPortSysTickHandler 并且在绿框位置开头位置添加 EXTERN vPortSVCHandler EXTERN xPortPendSVHandler EXTERN xPortSysTickHandler如上操作也可以上实现程序正常运行此篇完结。最后放上源码便于大家参考、调试、学习FreeRTOS移植STM32F103C8T6资料源码分享: 百度网盘提取码MCYC----来自一位不愿意透露姓名的百度用户的分享有什么问题可以留言或者私信找我我看到就会回没回就是没看到。其他参考资料/博客/文章参考链接: 超详细的FreeRTOS移植全教程——基于stm32参考链接: 【FreeRTOS】调用vTaskStartScheduler立即进入HardFault_Handler问题解决参考链接: Keil环境下STM32定位hardfault位置方法(addr2line工具)和遇到的情况更新信息发布于2026.9.30
RELATED

相关推荐

一张HTML页面搞定技能审查:Yao Meta Skill的Review Studio 2.0门禁详解

一张HTML页面搞定技能审查:Yao Meta Skill的Review Studio 2.0门禁详解

一张HTML页面搞定技能审查:Yao Meta Skill的Review Studio 2.0门禁详解 【免费下载链接】yao-meta-skill YAO Yielding AI Outcomes. A rigorous engineering, evaluation, governance, and portability system for reusable agent skills. 项目地址: https://gi…

📅 2026/10/1 22:03:38
Android 原生的 Compose A2UI 也来了,你还抱着 XML 养老吗?

Android 原生的 Compose A2UI 也来了,你还抱着 XML 养老吗?

Andorid Compose 的 A2UI 终于正式落地 AndroidX 了,这个我们在 Flutter 已经聊过很多次了,这次还是官方第一次通过 Compose Renderer 的形态落地到 Android。也就是 Android 原生也可以接收 A2UI 协议,然后通过 Agent 描述交互界面&#xff…

📅 2026/10/1 22:03:38
【架构专栏】补充2 数学与经济管理 1/2

【架构专栏】补充2 数学与经济管理 1/2

架构设计 相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 系统架构设计 相关文章: 【架构专栏】架构考试介绍 【架构专栏】架构知识点 知识总览​ 共19章内容,主要包括: 1)1绪论、2计算…

📅 2026/10/1 21:58:38
MORE NEWS

更多资讯

📰

LTTB下采样原理与Python实战:高效绘制十万点折线图

简介:本资源是一份面向Python数据处理开发者与算法学习者的LTTB(最大三角形三桶)下采样算法实战实现包,聚焦于高效保留时序或曲线数据局部特征的降采样需求,适用于大数据可视化、传感器数据压缩、前端图表性能优化等场…

📰

C语言网络编程:strcspn轻松清理CRLF回车符,终结字符串比较Bug

1. 现场还原:一个比对失败的“灵异”Bug 1.1 场景:C/S 模式下的指令分发 先说这次事故的背景。我的服务器程序用的是 C 语言,跑在 Linux 上,TCP 套接字接收客户端指令。客户端发过来的完成是字符,比如 LOGIN 、 GE…

📰

Python CNN验证码识别全流程:从样本生成到模型部署的工程实践

简介:基于Python与CNN神经网络的验证码识别项目,完整提供源码与文档说明,适合作为毕业设计、期末大作业或课程设计的高分参考。项目采用端到端卷积神经网络模型,对纯数字验证码的识别准确率可达99.99%,且代码包含详细注…

📰

Wine、FEX-Emu与DXMT:非x86平台运行Windows应用的兼容层实战

1. 从"Madeira"这个名字说起:一个跨平台兼容层的真实需求 第一次看到"Madeira"这个项目名,很多人会以为是某个度假岛屿或者葡萄酒品牌——毕竟马德拉岛确实以加强型葡萄酒出名。但放在当前的技术语境下,结合 Wine、FEX-E…

📰

北邮编译原理词法分析器:解决KEYWORD与ID识别冲突

简介:本资源是北京邮电大学《编译原理》课程实验一的完整实现包,面向计算机专业本科生及编译技术初学者,聚焦词法分析器的设计与编码实践,解决从理论规则到可运行代码的落地难题。压缩包共4个文件(2个txt文档、1个头文…

📰

Agent运行机制:上下文、检查点与任务恢复的工程实践

1. 从一次“执行中断”说起:为什么Agent不是跑完就完事的程序上周在调试一个电商客服Agent时,它在处理用户退货请求的第三步突然停住了。日志里只有一行冰冷的报错:agent execution terminated due to error.。没有堆栈,没有上下文…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬