STM32F103--移植FreeRTOS完整教程

article/2025/5/16 19:56:10

最近按照正点原子教程开始学习FreeRTOS,发现其手册的移植教程中有些地方可能不是那么详细,在此基于正点原子做一期最完整的FreeRTOS移植教程给大家。


小b将本次教程整理的资料放在网盘,以下链接供各位小伙伴下载和学习:
链接:https://pan.baidu.com/s/1z74dzFtQ198XLJwYhOVWlw
提取码:rson


  1. 打开FreeRTOS.exe文件,等待些许时间获取FreeRTOS源码
    在这里插入图片描述

  2. 拷贝库函数一个最简单的跑马灯实验工程作为待移植工程文件,并在基础工程中新建一个名为 FreeRTOS 的文件夹
    在这里插入图片描述

  3. 创建FreeRTOS文件夹之后将步骤1获取到的FreeRTOS文件下的FreeRTOSv9.0.0->FreeRTOS->Source中的全部文件全部拷贝到创建文件夹下
    在这里插入图片描述

  4. 其中为了工程轻简,protable文件夹下只留下以下三个文件夹:
    在这里插入图片描述

  5. 用keil打开工程文件,点击所示图标新建两个分组FreeRTOS_CORE 和 FreeRTOS_PORTABLE
    在这里插入图片描述

  6. 创建成功后左边工程栏出现对应两个分组,双击添加对应的文件如下图所示,其中FreeRTOS_CORE中的文件为源码直接打开可看到的.c文件,FreeRTOS_PORTABLE中的文件为port.c 是 RVDS 文件 夹下的 ARM_CM3 中的文件,因为 STM32F103 是 Cortex-M3 内核的,因此要选择 ARM_CM3 中的 port.c 文件,heap_4.c 是 MemMang 文件夹中的,因为heap_4 提供了一个最优的匹配算法,选择heap_4相关API进行内存管理。
    在这里插入图片描述

  7. 添加完FreeRTOS源码中的.c文件,接下来添加相应头文件的路径。点击如下图标进行设置:
    在这里插入图片描述

  8. 编译,发现缺少FreeRTOSConfig.h,他是FreeRTOS 的配置文件,一般的操作系统都有裁剪、配置功能,而这些裁剪及配置都是通过一个文件来完成的,基本都是通过宏定 义来完成对系统的配置和裁剪的。可以到FreeRTOS的demo里面相关的,但是不同硬件和环境配置不同,本操作采用正点原子的板子,直接拷贝一份正点原子STM32的FreeRTOSConfig.h到FreeRTOS的include目录下,再次进行编译

  9. 编译结果有错误,打开USER的system_stm32f0x_it.c,将以下报错两个函数屏蔽掉,编译成功
    在这里插入图片描述

  10. 修改sys.h文件
    在 sys.h 文件里面用宏 SYSTEM_SUPPORT_OS 来定义是否使用 OS, 我们使用了 FreeRTOS,所以应该将宏 SYSTEM_SUPPORT_OS 改为 1。
    在这里插入图片描述

  11. 更改delay.c
    delay.c需要修改比较多地方
    函数 SysTick_Handler():

extern void xPortSysTickHandler(void);//systick中断服务函数,使用ucos时用到
void SysTick_Handler(void)
{	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行{xPortSysTickHandler();	}
}

delay_init()函数:

//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8
//这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!
//SYSCLK:系统时钟频率
void delay_init()
{u32 reload;SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟  HCLKfac_us=SystemCoreClock/1000000;				//不论是否使用OS,fac_us都需要使用reload=SystemCoreClock/1000000;				//每秒钟的计数次数 单位为M  reload*=1000000/configTICK_RATE_HZ;			//根据configTICK_RATE_HZ设定溢出时间//reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右	fac_ms=1000/configTICK_RATE_HZ;				//代表OS可以延时的最少单位	   SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   	//开启SYSTICK中断SysTick->LOAD=reload; 						//每1/configTICK_RATE_HZ秒中断一次	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;   	//开启SYSTICK    
}	

剩下三个函数都是延时函数:

//延时nus
//nus:要延时的us数.	
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)	    								   
void delay_us(u32 nus)
{		u32 ticks;u32 told,tnow,tcnt=0;u32 reload=SysTick->LOAD;				//LOAD的值	    	 ticks=nus*fac_us; 						//需要的节拍数 told=SysTick->VAL;        				//刚进入时的计数器值while(1){tnow=SysTick->VAL;	if(tnow!=told){	    if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.else tcnt+=reload-tnow+told;	    told=tnow;if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.}  };										    
}  
//延时nms
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u32 nms)
{	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行{		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期 { vTaskDelay(nms/fac_ms);	 		//FreeRTOS延时}nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时    }delay_us((u32)(nms*1000));				//普通方式延时
}//延时nms,不会引起任务调度
//nms:要延时的ms数
void delay_xms(u32 nms)
{u32 i;for(i=0;i<nms;i++) delay_us(1000);
}

注意:delay_ms函数改完之后和头文件声明的不对应,需要到头文件delay.h更改下u16改成u32

最后,不要忘记将”includes.h”换成头文件”FreeRTOS.h”,并添加其他头文件如下图所示
在这里插入图片描述
其他无关的程序如:

#if SYSTEM_SUPPORT_OS							//如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS).
#ifdef 	OS_CRITICAL_METHOD						//OS_CRITICAL_METHOD定义了,说明要支持UCOSII	...
...OSTimeDly(ticks);							//UCOSII延时
#endif 
}

都可以删掉了。

  1. 更改usart.c
    usart.c 文件有两部分要修改,一个是添加 FreeRTOS.h 头文件, 默认是添加的 UCOS 中的 includes.h 头文件,修改以后如下:
    在这里插入图片描述
    另外一个就是 USART1 的中断服务函数,在使用 UCOS 的时候进出中断的时候需要添加 OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉,修改 以后如下:
void USART1_IRQHandler(void)                	//串口1中断服务程序
{u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾){Res =USART_ReceiveData(USART1);	//读取接收到的数据if((USART_RX_STA&0x8000)==0)//接收未完成{if(USART_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始else USART_RX_STA|=0x8000;	//接收完成了 }else //还没收到0X0D{	if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  }		 }}   		 } 
} 
  1. 直接将以下代码替换到main.c中的全部程序,编译烧录到板子中,有跑马灯现象证明成功。(本次实验使用的是战舰版,如果使用其他板可能需要稍作调整)
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
/************************************************ALIENTEK 战舰STM32F103开发板 FreeRTOS实验2-1FreeRTOS移植实验-库函数版本技术支持:www.openedv.com淘宝店铺:http://eboard.taobao.com 关注微信公众平台微信号:"正点原子",免费获取STM32资料。广州市星翼电子科技有限公司  作者:正点原子 @ALIENTEK
************************************************///任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define LED0_TASK_PRIO		2
//任务堆栈大小	
#define LED0_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);//任务优先级
#define LED1_TASK_PRIO		3
//任务堆栈大小	
#define LED1_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 delay_init();	    				//延时函数初始化	  uart_init(115200);					//初始化串口LED_Init();		  					//初始化LED//创建开始任务xTaskCreate((TaskFunction_t )start_task,            //任务函数(const char*    )"start_task",          //任务名称(uint16_t       )START_STK_SIZE,        //任务堆栈大小(void*          )NULL,                  //传递给任务函数的参数(UBaseType_t    )START_TASK_PRIO,       //任务优先级(TaskHandle_t*  )&StartTask_Handler);   //任务句柄              vTaskStartScheduler();          //开启任务调度
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           //进入临界区//创建LED0任务xTaskCreate((TaskFunction_t )led0_task,     	(const char*    )"led0_task",   	(uint16_t       )LED0_STK_SIZE, (void*          )NULL,				(UBaseType_t    )LED0_TASK_PRIO,	(TaskHandle_t*  )&LED0Task_Handler);   //创建LED1任务xTaskCreate((TaskFunction_t )led1_task,     (const char*    )"led1_task",   (uint16_t       )LED1_STK_SIZE, (void*          )NULL,(UBaseType_t    )LED1_TASK_PRIO,(TaskHandle_t*  )&LED1Task_Handler);         vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL();            //退出临界区
}//LED0任务函数 
void led0_task(void *pvParameters)
{while(1){LED0=~LED0;vTaskDelay(500);}
}   //LED1任务函数
void led1_task(void *pvParameters)
{while(1){LED1=0;vTaskDelay(200);LED1=1;vTaskDelay(800);}
}

学完有收获的小伙伴不妨点个赞支持一下小b呀~


http://chatgpt.dhexx.cn/article/Wdwn6GNF.shtml

相关文章

FreeRTOS 正点原子教程学习笔记

正点原子视频教程 FreeRTOS(教程非常详细&#xff09; 小知识 如果创建了任务却完全空着&#xff0c;没有while&#xff08;1&#xff09;{延时}的话&#xff0c;整个程序会卡住&#xff0c;其他正常的任务无法运行。如果任务里单单有赋值之类的操作也会卡死在这个任务&#…

FreeRTOS入门教程(堆和栈)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、FreeRTOS操作系统介绍二、堆1.概念介绍2.简单实现 三、栈总结 前言 本篇文章正式学习FreeRTOS操作系统&#xff0c;我打算编写一系列文章带大家轻松快速入…

FreeRTOS移植到STM32

一、找一个STM32的裸机工程模板 我们以STM32F103裸机程序为例 随便找的一个裸机程序 二、去官网上下载FreeRTOS V9.0.0 源码 在移植之前&#xff0c;我们首先要获取到 FreeRTOS 的官方的源码包。这里我们提供两个下载 链 接 &#xff0c; 一 个 是 官 网 &#xff1a; http:…

韦东山freeRTOS系列教程之【第一章】FreeRTOS概述与体验

文章目录 教程目录1.1 FreeRTOS目录结构1.1 FreeRTOS目录结构1.2 核心文件1.3 移植时涉及的文件1.4 头文件相关1.4.1 头文件目录1.4.2 头文件 1.5 内存管理1.6 Demo1.7 数据类型和编程规范1.7.1 数据类型1.7.2 变量名1.7.3 函数名1.7.4 宏的名 1.8 安装Keil1.8.1 下载Keil1.8.2…

freeRTOS中文实用教程1

资料转载出处 https://www.cnblogs.com/smartjourneys/p/7073450.html 1.前言 FreeRTOS是小型多任务嵌入式操作系统&#xff0c;硬实时性。本章主要讲述任务相关特性及调度相关的知识。 任务的总体特点 任务的状态 &#xff08;1&#xff09;任务有两个状态&#xff0c;运行态…

FreeRTOS入门

目录 一、简介 二、堆的概念 三、栈的概念 四、从官方源码中精简出第一个FreeRTOS程序 五、修改官方源码增加串口打印 一、简介 FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统&#xff0c;功能包括&#xff1a;任务管理、时间管理、信号量、消息队列、…

freeRTOS系列教程之【第一章】FreeRTOS概述与体验

文章目录 教程目录1.1 FreeRTOS目录结构1.1 FreeRTOS目录结构1.2 核心文件1.3 移植时涉及的文件1.4 头文件相关 1.4.1 头文件目录1.4.2 头文件 1.5 内存管理1.6 Demo1.7 数据类型和编程规范 1.7.1 数据类型1.7.2 变量名1.7.3 函数名1.7.4 宏的名 1.8 安装Keil 1.8.1 下载Keil1.…

【机器学习】3-4-2 流行学习

#3-4-2流行学习 import mglearn import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.datasets import load_breast_cancer from sklearn.datasets import make_moons from sklearn.datasets import make_blobs from sklearn.datasets impor…

【机器学习】(十八)用t-SNE进行流行学习:手写数字分类

PCA是用于变换数据的首选方法&#xff0c;也可以进行可视化&#xff0c;但它的性质&#xff08;先旋转然后减少方向&#xff09;限制了有效性。 流行学习算法&#xff1a;是一类用于可视化的算法&#xff0c;它允许进行更复杂的映射&#xff0c;通常也可以给出更好的可视化。t-…

用Python实现流行机器学习算法

对于此库的Octave/MatLab版本&#xff0c;请检查machine-learning-octave项目。 该库包含在Python中实现的流行机器学习算法的示例&#xff0c;其中包含数学背后的解释。 每个算法都有交互式Jupyter Notebook演示&#xff0c;允许您使用训练数据&#xff0c;算法配置&#xff0…

【流行学习】局部线性嵌入(Locally Linear Embedding)

一、前言 局部线性嵌入&#xff08;LLE&#xff09;假设数据在较小的局部是线性的&#xff0c;也就是说&#xff0c;某一个样本可以由它最近邻的几个样本线性表示&#xff0c;离样本远的样本对局部的线性关系没有影响&#xff0c;因此相比等距映射算法&#xff0c;降维的时间复…

流行-Manifold学习理解与应用

流行-Manifold【1】 流形&#xff0c;也就是 Manifold 。 1. 比较好的形象理解 流形学习的观点是认为&#xff0c;我们所能观察到的数据实际上是由一个低维流形映射到高维空间上的&#xff0c;即这些数据所在的空间是“嵌入在高维空间的低维流形。”。由于数据内部特征的限制&a…

【流行学习】拉普拉斯映射(Laplacian Eigenmaps)

一、前言 拉普拉斯特征映射是一种基于图的降维算法&#xff0c;它希望在原空间中相互间有相似关系的点&#xff0c;在降维后的空间中尽可能的靠近&#xff0c;从而在降维后仍能保持原有的数据结构信息。 二、主要步骤 拉普拉斯特征映射通过构建邻接矩阵为 W W W&#xff08;…

7个流行的强化学习算法及代码实现

目前流行的强化学习算法包括 Q-learning、SARSA、DDPG、A2C、PPO、DQN 和 TRPO。 这些算法已被用于在游戏、机器人和决策制定等各种应用中&#xff0c;并且这些流行的算法还在不断发展和改进&#xff0c;本文我们将对其做一个简单的介绍。 1、Q-learning Q-learning&#xff1…

流行学习,比较好的一篇博客

转载自&#xff1a;https://blog.csdn.net/sinat_32043495/article/details/78997758 嵌入在高维空间的低维流形 流形&#xff1a;局部具有欧几里得空间性质的空间 1.较好的描述转载 作者&#xff1a;暮暮迷了路 链接&#xff1a;https://www.zhihu.com/question/2401548…

深度学习—近年来流行的卷积神经网络(一)

近年来流行的卷积神经网络 1. 回顾与目标2. 近年来流行的卷积神经网络2.1 VGGNet2.1.1 感受野的概念2.1.2 感受野的计算 2.2 GooleNet2.3 ResNet 3. 结尾参考资料 1. 回顾与目标 前面几讲&#xff0c;我们以LeNet和AlexNet为例&#xff0c;详细讲解了卷积神经网络的结构。从20…

流行学习常用算法

Isomap&#xff1a;等距映射。前提假设为低维空间中的欧式距离等于高维空间中的侧地线距离&#xff0c;当然该算法具体实施时是高维空间中较近点之间的测地线距离用欧式距离代替&#xff0c;较远点距离用测地线距离用最短路径逼近。 LLE:局部线性嵌入。前提假设是数据所在的低维…

流行学习与拉普拉斯变换的推导

参考&#xff1a;拉普拉斯矩阵 参考&#xff1a;流行学习

流行学习初步理解

一. 流形学习的英文名为manifold learning。其主要思想是把一个高维的数据非线性映射到低维&#xff0c;该低维数据能够反映高维数据的本质&#xff0c;当然有一个前提假设就是高维观察数据存在流形结构&#xff0c;其优点是非参数&#xff0c;非线性&#xff0c;求解过程简单。…

流行学习简单入门与理解

最近博主再看西瓜书第十三章半监督学习&#xff0c;文章中作者提到需要少量查询的主动学习、K-means簇的聚类&#xff0c;以及流行学习。对于流行学习&#xff0c;博主也是第一次接触&#xff0c;下面我们来简单学习和理解一下流行学习。 1. 半监督学习 SSL的成立依赖于模型假…