[STM32]从零开始的STM32 FreeRTOS移植教程
一、前言
如果能看到这个教程的话,说明大家已经学习嵌入式有一段时间了。还记得嵌入式在大多数时候指的是什么吗?是的,我们所说的学习嵌入式大部分时候都是在学习嵌入式操作系统。从简单的一些任务状态机再到复杂一些的RTOS,再到最复杂的Linux,这些都属于嵌入式操作系统的一种,只是简单与复杂的区别。在之前,我们开发STM32时采用的都是裸机开发所以对实时系统并没有什么概念,接触RTOS会接触到一种新的编程方式。当然,因为RTOS已经引入了系统的概念了,所以代码看起来与调试起来也更加抽象。但,就现在而言,实时操作系统仍然是许多公司要求嵌入式工程师必会的技能之一。所以,如果你准备好了,就让我们一起来移植RTOS吧!
二、在开始之前
因为已经涉及到嵌入式系统了,所以还请学习这篇教程的小伙伴有一定的STM32基础,我始终不推荐纯小白直接接触RTOS。在这篇教程中,我会教大家如何下载RTOS的代码固件包,如何将RTOS移植到对应的单片机中,以及如何解决一些常见的问题。当然,你也可以下载我下面给的资料,资料中会包含本次会用到的RTOS源码包和我已经移植好的工程:
RTOS移植资料:https://pan.baidu.com/s/1YbfUm1LUSomslaGWqJ-g4w?pwd=clxm
提取码:clxm
三、芯片的选择
因为RTOS是一个嵌入式操作系统,RTOS强调的是代码的实时性,比起裸机开发,它并不能提高芯片的性能,相反,它是一个消耗芯片性能的软件。在运行了RTOS以后,我们芯片的资源就被占用了一部分,这也会让我们的可编程范围变小了。既然是这样,那为什么我们还需要嵌入式操作系统呢?当然是为了实时性呀,裸机在开发时,代码始终顺序执行,这也导致了我们有的步骤要等很久才会执行到,在某些特定的情况下就可能出现问题。如果使用实时操作系统,它会合理分配每一个任务的执行时间,保证我们每一个任务都执行一段时间,不会有任务长期阻塞程序。当然,我们这次的重点并不是RTOS的原理,如果想要了解RTOS详细原理与系统性的学习的话,还是建议大家去看一些视频教程。这里话又说回来,因为RTOS会消耗一部分的性能,所以有的芯片可能无法运行RTOS,这里我会使用STM32F407ZGT6进行RTOS的移植演示,我并不推荐大家使用STM32F103C6T6单片机,这款单片机在移植RTOS时可能会出现你无法解决的错误。在移植RTOS时尽量选择RAM与ROM都比较大的芯片。这样代码在编译时也不容易报错。
四、RTOS系统固件包的下载
RTOS的虽说是一个操作系统,但是本质上还是代码构成的,在这里面我们仍然可以看到.c .h文件。所以,移植RTOS简单来说,就是将对应的C语言代码在STM32中运行起来。所以我们现在需要下载RTOS的固件包,这里我们直接在浏览器中搜索“FreeRTOS”:
我们可以看到,这里搜索出来的第一个网站就是FreeRTOS的官网了:
当然,如果你没有找到FreeRTOS的官网的话,也可以点击下方的链接前往:
FreeRTOS官网:FreeRTOS™ - FreeRTOS™
进入FreeRTOS的官网以后,就可以看到以下页面了:
如果你这里不是中文的,可以点击右上角这里切换语言:
接着,我们点击网页中的“下载”:
点击了下载以后,弹出的窗口中会让我们选择要下载的版本:
这里我推荐大家使用2022或者2020的版本,这些版本经过了几年的迭代已经非常稳定了。如果你是小白的话,建议下载和我一样的版本,以保证文件的统一。
我们选择好版本以后,直接点击“Download”:
随后浏览器就会弹出下载了:
我们将其下载到我们能找到的地方:
如果你这里无法打开RTOS的官网或者是无法下载RTOS的固件包,那么你就可以打开我给的资料中的RTOS固件包文件夹,这里有我已经下载好的固件包:
下面,我们再将下载的压缩包解压得到以下文件夹:
至此,我们RTOS系统的固件包就已经下载完成了。
五、RTOS的移植
当我们准备好了RTOS系统的固件包以后,就可以开始移植了,这里我们移植RTOS系统是在原本的工程之上,所以,首先就要保证我们有一个对应芯片的对应工程模板。我这里使用的是STM32F407ZGT6芯片,所以准备的也是STM32F407ZGT6的工程,如图:
我们进入工程,这里需要我们的工程编译没有错误:
下面我们直接写一个LED的代码,证明我们的硬件没有问题,这个地方的点灯代码很简单,就不多说了,我的LED在PA12口上,并且为高电平点亮:
将程序编译下载到芯片后,就可以看到LED已经亮起了,证明我们的硬件方面没有问题:
下面,我们就要在这个原本的工程上移植RTOS。
首先需要在工程的主目录下新建一个RTOS的文件夹用来存放RTOS的相关文件:
我们进入这个RTOS的文件夹,然后新建三个文件夹,分别是“inc”,“src”,“port”:
这里的inc文件夹用来存放RTOS的头文件和配置文件,src用来存放RTOS的源文件,port用来存放RTOS的内存管理文件。
我们现在去RTOS固件包解压出来的文件夹中复制文件,我们进入解压后的文件夹就可以看到以下文件夹和文件:
这里我们再进入“FreeRTOSv202212.01”文件夹下的“FreeRTOS”文件夹,可以看到以下文件和文件夹:
然后我们再进入“FreeRTOS”文件夹下的“Source”文件夹,这里面的文件就是我们要用的了:
这里我们首先将“Source”文件夹下的所有.c的文件复制到刚才工程目录中创建的“RTOS\src”文件夹下:
这里需要注意的是,我们只需要复制.c,多余的文件如果被复制过去了删除就行了。
随后,我们再把“Source”文件夹下的“include”文件夹下的所有.h的文件复制到“RTOS\inc”文件夹下
这里同样的只要.h文件,不能复制别的文件。
随后我们进入“Source”文件夹下的“portable”文件夹,看到以下文件夹:
这里包含了RTOS的内存管理文件和不同编译器的相关文件。这里我们首先来复制内存管理文件,我们进入“portable”文件夹下的“MemMang”文件夹,将“heap_4.c”文件复制到工程目录下的“RTOS\port下”:
这里的内存管理文件我们一般都用4,如果你是小白的话请不要随意修改。
随后我们再打开“portable”文件夹下的“RVDS”文件夹,可以看到以下文件夹:
这里面对应了RVDS集成编译环境不同的ARM内核的编译规则文件。因为我这里使用的是STM32F407ZGT6单片机,所以这里首先肯定要选择M4内核,因为STM32F407ZG系列都不附带MPU所以我们这里直接选择“ARM_CM4F”文件夹,我们将“RVDS\ARM_CM4F”下的文件复制到工程目录下的“RTOS\port”下:
至此,我们RTOS的基本文件就已经复制完成了,这里我们还需要复制一下配置文件。配置文件被放在了“FreeRTOSv202212.01\FreeRTOS\Demo”目录下,进入这个目录,我们就能看到非常多的芯片型号,这些芯片官方都提供的相关的Demo,我们只需要在对应的芯片Demo中寻找配置文件即可:
因为这里我使用的是STM32F407ZGT6的芯片,所以我芯片所对应的配置文件就被存放在了“CORTEX_M4F_STM32F407ZG-SK”文件夹下。大家可以根据自己的芯片型号和对应的IDE寻找相关的Demo:
这里我们进入“CORTEX_M4F_STM32F407ZG-SK”文件夹,文件夹中的“FreeRTOSConfig.h”就是我们需要的配置文件了,我们将其复制到工程目录下的“RTOS\inc”下:
至此,我们RTOS运行所需的所有文件都已经复制完成了,我们直接打开工程:
接着,我们把刚才复制的文件添加的工程中,点击菜单栏中的箱子:
我们这里新建三个文件夹,分别是“RTOS\inc”,“RTOS\src”,“RTOS\port”:
接着将对应文件夹中的文件添加进来,这里一定要对应好,不要添加错了:
这里要注意的是,一定是把对应的所有文件添加进来以后再进行下一步。
我们再在魔术棒中将对应文件夹的路径添加进来,这里路径添加很基础,就不细讲了:
将文件添加进来以后,我们点击编译,这里的编译肯定会报错的,我们慢慢来解决:
这里的错误提示我们“configSYSTICK_CLOCK_HZ”这个变量没有定义。这里我们去到配置文件中,大概在40行左右,可以看到这样一条条件编译:
这里是为了判断是否是使用IAR编译器,我们这里使用的是keil,这条条件编译肯定不会过的。我们将这一条条件编译修改一下,改成下面这样:
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
这里修改了条件编译以后就可以兼容keil,IAR, GCC编译器了。
我们再次编译,出现三个重复定义的错误,因为这三个函数在STM32原本的库中已经被定义过了,但是在RTOS的库中又被定义了一次。既然我们要使用RTOS那当然也要用RTOS的处理函数,这里我们直接将原本的函数注释掉:
原本的函数被写在了“stm32f4xx_it.c”中,我们分别将其注释掉,通过报错我们可以得知,这里被重复定义的函数分别是“PendSV_Handler”,“SVC_Handler”,“SysTick_Handler”:
注释后如图:
这里将重复定义的函数注释掉以后,我们再次编译,我们可以看到这几个函数没有被定义:
这里又需要我们修改配置文件了,我们同样的打开配置文件我们将配置文件中的如下几项的值改为0:
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
修改完配置文件以后,我们再次编译:
可以看到,现在已经没有报错了,我们现在就算是移植完成了,我们可以写一点代码来试一下,首先回到“main.c”,这里我们先在main.c中引入RTOS相关的头文件:
#include "freertos.h"
#include "task.h"
然后我们创建一个任务函数:
void LED(void* age)
{while(1){GPIO_ResetBits(GPIOA,GPIO_Pin_12);vTaskDelay(500);GPIO_SetBits(GPIOA,GPIO_Pin_12);vTaskDelay(500);}
}
这里就是我们的任务函数了,控制了LED的亮灭,注意,任务函数进入以后一定是在一个死循环中,任务函数不能返回,不然可能引发一些错误。在使用了RTOS以后,我们的所以延时都要使用RTOS中的相对延时。
在主函数中,我们写引脚的初始化和任务的创建:
int main(void)
{TaskHandle_t myTaskHandle_t;GPIO_InitTypeDef GPIO_InitStructure;delay_init(168);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_12);xTaskCreate(LED,"LED",128,NULL,2,&myTaskHandle_t);vTaskStartScheduler();while(1){}
}
这里主要解释一下“xTaskCreate”函数。xTaskCreate用于创建RTOS中的任务。这里的第一个参数为任务函数的名称,我们这里任务函数名为“LED”所以第一个参数就传入LED,第二个参数是任务的名字,要求传入字符串格式的,我们这里传入一个字符串即可。第三个参数是为任务分配的内存,我们这里的任务只是点灯而已,所以不用分配太大,直接128就已经很充足了。第四个参数是向任务中传入的参数,我们这里没有参数要传入,直接写NULL,第五个参数是任务的优先级,因为只有一个任务,也不存在谁优先的问题,随便写个优先级即可。最后要我们传入一个“TaskHandle_t ”类型的结构体指针,我们直接定义一个结构体,取它的地址传入即可。
随后,我们再使用vTaskStartScheduler函数启动任务调度器。当调度器启动以后,STM32就已经被系统接管了。
我们将代码编译下载到开发板中,可以看到LED正常闪烁:
至此,我们的RTOS已经算是移植成功了。当然RTOS的知识还很多,能够运用只是第一步。
六、结语
本次我们讲解了如何下载RTOS的固件包,以及如何复制RTOS的相关文件,以及在遇到错误以后如何解决。内容比较多,还是希望大家多吸收一下。那么最后,感谢大家的观看!
相关文章:
[STM32]从零开始的STM32 FreeRTOS移植教程
一、前言 如果能看到这个教程的话,说明大家已经学习嵌入式有一段时间了。还记得嵌入式在大多数时候指的是什么吗?是的,我们所说的学习嵌入式大部分时候都是在学习嵌入式操作系统。从简单的一些任务状态机再到复杂一些的RTOS,再到最…...
java——Tomcat连接池配置NIO、BIO、APR
Tomcat连接池的配置涉及不同的IO模型,包括NIO(Non-blocking IO,非阻塞IO)、APR(Apache Portable Runtime,Apache可移植运行库)和BIO(Blocking IO,阻塞IO)。以…...
跨域相关的一些问题 ✅
当网页从一个源(https://baidu.com)请求另一个源(如 https://taobao/api)的资源时,就发生了跨域。由于安全原因(防止恶意网站通过脚本访问用户在其他网站上的数据),浏览器对跨域请求…...
RPC学习
一、什么是 RPC RPC(Remote Procedure Call),即远程过程调用,是一种计算机通信协议,它允许运行在一台计算机上的程序调用另一台计算机上的子程序或函数,就好像调用本地程序中的函数一样,无需程序…...
coe文件转mif(c语言)
1 mif文件格式 DEPTH=1024; --The size of data in bits WIDTH=16; --The size of memory in words ADDRESS_RADIX = DEC; --The radix for address values DATA_RADIX = UNS...
【leetcode】动态规划
31. 873. 最长的斐波那契子序列的长度 题目: 如果序列 X_1, X_2, ..., X_n 满足下列条件,就说它是 斐波那契式 的: n > 3对于所有 i 2 < n,都有 X_i X_{i1} X_{i2} 给定一个严格递增的正整数数组形成序列 arr ࿰…...
介绍一下atoi(arr);(c基础)
hi , I am 36 适合对象c语言初学者 atoi(arr);是返回整数(int型),整数是arr数组中字符中数字 格式 #include<stdio.h> atoi(arr); 返回值arr数组中的数字 未改变arr数组 #include<stdlib.h>//atoi(arr); 返 <stdlib> int main(…...
docker入门学习笔记
docker的定义 docker是一个用于构建、运行、传送 应用程序的平台。 为什么要使用docker ? 在开发测试库环境中测试成功后,打包成集装箱,到生产环境也是能够成功的。而传统的安装方式不仅繁琐,并且在测试环境安装后,到…...
使用Python和Pybind11调用C++程序(CMake编译)
目录 一、前言二、安装 pybind11三、编写C示例代码四、结合Pybind11和CMake编译C工程五、Python调用动态库六、参考 一、前言 跨语言调用能对不同计算机语言进行互补,本博客主要介绍如何实现Python调用C语言编写的函数。 实验环境: Linux gnuPython3.10…...
tableau-制作30个图表
制作条形图 步骤: 1、横轴是数值,对应了某一个度量值,纵轴是一个标签 战区的成交额,条形图横轴是战区,纵轴是成交额 下钻条形图 1、增加业务架构-战区右键点击,分层结构,增加分层结构 调整业务架构,将战区,城市,小组移动到业务架构下方 此时的条形图上方有➕号展开后…...
2024APMCM亚太杯数学建模C题【宠物行业】原创论文分享
大家好呀,从发布赛题一直到现在,总算完成了2024 年APMCM亚太地区大学生数学建模竞赛C题的成品论文。 给大家看一下目录吧: 目录 摘 要: 10 一、问题重述 14 二.问题分析 15 2.1问题一 15 2.2问题二 15 2.3问题三…...
C语言解析命令行参数
原文地址:C语言解析命令行参数 – 无敌牛 欢迎参观我的个人博客:无敌牛 – 技术/著作/典籍/分享等 C语言有一个 getopt 函数,可以对命令行进行解析,下面给出一个示例,用的时候可以直接copy过去修改,很方便…...
推荐一款龙迅HDMI2.0转LVDS芯片 LT6211UX LT6211UXC
龙迅的HDMI2.0转LVDS芯片LT6211UX和LT6211UXC是两款高性能的转换器芯片,它们在功能和应用上有所差异,同时也存在一些共同点。以下是对这两款芯片的详细比较和分析: 一、LT6211UX 主要特性: HDMI2.0至LVDS和MIPI转换器。HDMI2.0输…...
libmodbus 源码学习笔记
1.核心函数_框架_数据结构 整个通信的过程 就是上面这个框架 下面就是具体过程 <1> 主设备 我们首先要初始化 我们要使用的串口 然后 设置我们要访问的哪一个设备 最后打开串口 <2>从机设备 也是我们要初始化我们的串口 然后随后立即设置我们的串口设备地址 最后…...
通用网络安全设备之【防火墙】
概念: 防火墙(Firewall),也称防护墙,它是一种位于内部网络与外部网络之间的网络安全防护系统,是一种隔离技术,允许或是限制传输的数据通过。 基于 TCP/IP 协议,主要分为主机型防火…...
Vue.js基础——贼简单易懂!!(响应式 ref 和 reactive、v-on、v-show 和 v-if、v-for、v-bind)
Vue.js是一个渐进式JavaScript框架,用于构建用户界面。它专门设计用于Web应用程序,并专注于视图层。Vue允许开发人员创建可重用的组件,并轻松管理状态和数据绑定。它还提供了一个虚拟DOM系统,用于高效地渲染和重新渲染组件。Vue以…...
Mybatis 执行存储过程,获取输出参数的值
数据库环境:SQL Server 2008 R2 存储过程 alter procedure proc_generateOuterApplyId acceptType varchar(4),acceptGroupId int,outerApplyId varchar(20) output as begin set nocount onset outerApplyId 24GD6688--select outerApplyId as …...
RAG架构类型
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
Oracle 数据库 IDENTITY 列的性能选项
在上一篇文章Oracle 数据库 IDENTITY 列中,我们介绍了Oracle IDENTITY列的基础知识。本文将介绍IDENTITY列的几个性能选项。由于IDENTITY列内部使用sequence机制,因此也等同于是sequence的性能选项。 由于sequence是递增的,在高并发时&#…...
计算(a+b)/c的值
计算(ab)/c的值 C语言代码C语言代码Java语言代码Python语言代码 💐The Begin💐点点关注,收藏不迷路💐 给定3个整数a、b、c,计算表达式(ab)/c的值,/是整除运算。 输入 输入仅一行&…...
OpenCV从入门到精通实战(八)——基于dlib的人脸关键点定位
本文使用Python库dlib和OpenCV来实现面部特征点的检测和标注。 下面是代码的主要步骤和相关的代码片段: 步骤一:导入必要的库和设置参数 首先,代码导入了必要的Python库,并通过argparse设置了输入图像和面部标记预测器的参数。…...
unity | 动画模块之卡片堆叠切换
一、预览动画 可以放很多图,可以自己往后加,可以调图片x轴和y轴间距,可以调图片飞出方向,可以调堆叠方向。 图1 图片堆叠动画预览 二、纯净代码 有粉丝问我这个效果,最近很忙,没有时间细写,先…...
前端开发工程师需要学什么?
前端开发工程师需要学习的主要内容包括HTML、CSS、JavaScript、前端框架、响应式设计、性能优化、版本控制等。 HTML/CSS/JavaScript HTML:是网页的骨架,负责网页的结构和内容。CSS:用于美化网页,设计样式和布局。…...
网络常见命令
一.添加ip地址 (1)先进入端口号 interface 端口号 (2)添加ip地址 IP address xxx.xxx.x.x 主机位 二、查看路由表(查看192.168.3.1) display ip routing-table 192.168.3.1 三、宣告(宣告完后…...
logminer挖掘日志归档查找问题
--根据发生问题时间点查找归档文件 select first_time,NAME from gv$archived_log where first_time>2016-03-15 17:00:00 and first_time<2016-03-15 21:00:00; 2016-03-15 17:23:55 ARCH/jxdb/archivelog/2016_03_15/thread_1_seq_41588.4060.906577337 2016-03-15 17:…...
Flume和kafka的整合:使用Flume将日志数据抽取到Kafka中
文章目录 1、Kafka作为Source【数据进入到kafka中,抽取出来】2、kafka作为Sink 【数据从别的地方抽取到kafka里面】 1、Kafka作为Source【数据进入到kafka中,抽取出来】 kafka源 --> memory --> 控制台: a1.sources r1 a1.sinks k1…...
springboot实战(19)(条件分页查询、PageHelper、MYBATIS动态SQL、mapper映射配置文件、自定义类封装分页查询数据集)
引言: 该类博客的学习是基于b站黑马视频springbootvue视频学习!具体围绕项目——"大事件"进行实战学习。 目录 一、功能介绍(需求)。 1、文章列表功能基本介绍。 2、条件分页查询功能与注意。 3、前端页面效果。&#x…...
ScreenshotToCode安装教程
网页截图生成代码,我测试的效果一般 快速安装教程如下 1,首先你得有OpenAI的账号 国内用这个代理就可以: https://www.closeai-asia.com/ 充值一块钱,在本项目中可以生成两次 2,下载程序 下载程序压缩包࿱…...
最佳实践:如何在 Vue.js 项目中使用 Jest 进行单元测试
前言 随着应用程序规模和复杂性的增加,保证代码质量和稳定性变得愈发重要。单元测试作为软件测试的一部分,能够有效地捕捉代码中的错误,防止在开发过程中引入新的 Bug。在众多测试框架中,Jest 因其易用性、强大功能以及与 Vue.js…...
MySQL 与 MongoDB 存储差异分析
MySQL 与 MongoDB 存储差异分析:为什么随机生成数据的存储空间不同? 在实际应用中,我们常常需要选择合适的数据库系统来处理不同类型的数据。在这个过程中,数据库的 存储机制 和 性能优化 起着至关重要的作用。对于很多开发者来说…...
吴江城乡住房和城乡建设局网站/拼多多关键词排名查询
document.addEventListener(blur,function(){document.body.scrollIntoView(false)},true) })复制代码...
电商平台要投资多少钱/sem优化技巧
最近爱上了霉霉的歌曲《love story》,想要到网上下载钢琴谱,但完整的大多都是需要付费的,为了贯彻个人理念,那当然是能白嫖就不放过啦,在此我也顺带教一教大家不使用编程语言,如何爬取网页上不能下载的图片…...
怎么制作网站小游戏/seo公司 杭州
如何搭建知识付费系统?如何搭建一个知识付费课程平台知识付费一直很火爆,在这个不确定的时代,很多人已经明确知道,学习是终身的事情,也有人在说这只是在制造焦虑,但知识付费越来越火是个明确的事实。这就有…...
做好公司网站/山西百度查关键词排名
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面…...
怎么做农家乐联盟网站/公关服务
原标题:不会还有人不知道可以用小程序加入腾讯会议吧?!大家都知道腾讯的生态是非常厉害的,上至游戏、音视频,下到社交、论坛,腾讯的软件可谓是服务到了日常工作学习生活包括娱乐各个方面了,加上…...
网站设计制作报价/站长
前几天在交流IOC的时候,提到了静态类的写法,我的一个误区静态类 长这个样子: public static class StaticClass{//TODO } 然鹅,“事与愿违”,静态类直接在class前加入"static"在Java中是一种错误的写法…...