STM32第十九课:FreeRTOS移植和使用
创始人
2025-01-07 06:04:03
0

目录

  • 需求
  • 一、FreeRtos概要
  • 二、移植FreeRtos
    • 1.复制源码
    • 2.内存空间分配和内核相关接口
    • 3.FreeRTOSConfig.h
    • 4.在工程中添加.c.h
  • 三、任务块操作
    • 1.创建任务
    • 2.任务挂起,恢复,删除
  • 四、需求实现代码


需求

1.将FreeRtos(嵌入式实时操作系统)移植到STM32中。
2.在该系统中实现任务的创建、挂起、恢复和删除。
3.将之前写的传感器模块的数据获取,移植到FreeRtos(嵌入式实时操作系统)环境下。
在这里插入图片描述
在这里插入图片描述


一、FreeRtos概要

STM32裸机运行代码:
在这里插入图片描述
加入FreeRtos后:
在这里插入图片描述
由此可见,由于单片机只有一个核心,同一时间下只能处理一件事。如果用户想要实现多个任务并行的效果,可以通过加入FreeRtos(嵌入式实时操作系统),操作系统可以让STM32实现任务的快速切换,从而给人一种多个任务并行的错觉。
在这里插入图片描述

二、移植FreeRtos

  打开想要移植FreeRtos的工程,把主函数清空,只留一个while(1)。由于FreeRtos是任务块操作,所以之前写的程序就没用了。
移植后使用了三个中断服务函数:
1.SVC中断服务函数:上下切换中断,FreeRtos实现任务切换
2.PendSVC中断服务函数:任务挂起中断。
3.SysTick中断服务函数:FreeRtos运行的时间基准

#define vPortSVCHandler SVC_Handler	  //上下切换中断,FreeRtos实现任务切换 #define xPortPendSVHandler PendSV_Handler		//任务挂起中断 #define xPortSysTickHandler SysTick_Handler	//FreeRtos运行的时间基准 

1.复制源码

先打开移植的文件夹:

在这里插入图片描述
将源码直接复制到想要移植的工程文件下,改名为FreeRtos:
在这里插入图片描述

2.内存空间分配和内核相关接口

在这里插入图片描述
在portable文件夹中找到MemMang文件夹,该文件夹放着的就是内存分配文件,我们选择4就行。
在这里插入图片描述
port,就是内核相关的接口文件,是必要添加的。

3.FreeRTOSConfig.h

在这里插入图片描述
打开样例文件夹,找到相对应的芯片,将FReeRTOSconfig.h文件复制过来即可。

4.在工程中添加.c.h

.c
在这里插入图片描述
.h
在这里插入图片描述

其中,FreeRTOSConfig.h 是直接从 demo 文件夹下面拷贝过来的,该头文件对裁剪整个FreeRTOS 所需的功能的宏均做了定义,有些宏定义被使能,有些宏定义被失能,一开始我们只需要配置最简单的功能即可。要想随心所欲的配置 FreeRTOS 的功能,必须对这些宏定义的功能有所掌握。

#define configUSE_TIME_SLICING 1 //使能时间片调度(默认式使能的) #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 //硬件计算前导零指令,如果所使用的, MCU 没有这些硬件指令的话此宏应该设置为 0 #define configUSE_TICKLESS_IDLE 0 //置 1:使能低功耗 tickless 模式;置 0:保持系统节拍(tick)中断一直运行 #define configUSE_QUEUE_SETS 1 //启用队列 #define configUSE_TASK_NOTIFICATIONS 1 //开启任务通知功能,默认开启 #define configUSE_MUTEXES 1 //使用互斥信号量 #define configUSE_RECURSIVE_MUTEXES 1 //使用递归互斥信号量 #define configUSE_COUNTING_SEMAPHORES 1 //为 1 时使用计数信号量 #define configQUEUE_REGISTRY_SIZE 10 //设置可以注册的信号量和消息队列个数 #define configUSE_APPLICATION_TASK_TAG 0 #define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请 #define configUSE_MALLOC_FAILED_HOOK 0 //使用内存申请失败钩子函数 #define configCHECK_FOR_STACK_OVERFLOW 1// 大于 0 时启用堆栈溢出检测功能,如果使用此功能用户必须提供一个栈溢出钩子函数如果使用的话此值可以为 1 或者 2,因为有两种栈溢出检测方法 #define configGENERATE_RUN_TIME_STATS 0 //启用运行时间统计功能 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 #define configUSE_TIMERS 1 //启用软件定时器 #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级 #define configTIMER_QUEUE_LENGTH 10 //软件定时器队列长度 #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小 //可选函数配置选项 #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_eTaskGetState 1 #define INCLUDE_xTimerPendFunctionCall 1 //中断服务函数 也可以修改起始文件 #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler 

三、任务块操作

调度
和裸机操作不同,操作系统中执行的是一个一个任务块,通过任务调度器(使用相关的调度算法)来决定当前时刻要执行哪个任务。
调度方式主要有两种:
1.抢占式调度:任务优先级不同时使用。每个任务都有自己的优先级,高优先级的任务会抢占低优先级的任务。
2.时间片调度:任务优先级相同时使用。当多个任务优先级相同时,任务调度器会在每一次系统节拍到的时候切换任务。
其实说白了就是:STM32执行的是线性代码,只有中断能打断。而FreeRtos执行的是不同等级的任务块,等级越高任务块就越先执行相同等级的任务块执行时系统会来回切换
优先级不能设置为0,因为FreeRtos的空闲任务优先级为0,一般情况下我们不去抢。

任务状态

状态含义
运行态CPU正在执行的任务。注意:在STM32中,同一时间仅一个任务处于运行态
就绪态该任务能够被执行,但目前还未被执行,那么该任务就处于就绪态。
阻塞态如果一个任务因延时或等待外部事件发生,那么这个任务就处于阻塞态。
挂起态类似暂停,调用函数 vTaskSuspend() 进入挂起态,需要调用恢复函数vTaskResume()才可以进入就绪态 。

1.创建任务

添加FreeRTOS相关头文件

//使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h" #include "FreeRtos.h" #include "task.h" 

创建一个句柄,TaskHandle_t 类型

TaskHandle_t LED_TaskHandle;//LED 

写与句柄对应的任务函数,通常要加while(1)每个任务都是1个无限循环程序,内容根据需求来定。

void Led_Task(void *p) { 	uint8_t i=0; 	while(1) 	{ 		i++; 		printf("i=%d\r\n",i); 		Led_Toggle(1); 		Delay_nms(300); 	} }  

定义一个BaseType_t变量

BaseType_t Ret = pdPASS; 

使用xTaskCreate()创建任务块,返回值由BaseType_t类型变量承接,返回值为pdPASS(1)时即创建成功

	Ret = xTaskCreate(  Led_Task,                        "LED1_toggle",                         50,//栈深度,32位单片机*4                         NULL, 						2,                         &LED_TaskHandle                      ); 	if(Ret==pdPASS) 	{ 		printf("LED_Task创建成功!\r\n"); 	} 

参数1:实现任务的函数名
参数2:自己起一个任务名
参数3:分配空间,栈深度(32位单片机*4)
参数4:任务函数传参时使用
参数5:任务优先级(越高优先级越高)
参数6:该任务的句柄

最后,使用vTaskStartScheduler()函数开始调度就完成了。

vTaskStartScheduler(); 

2.任务挂起,恢复,删除

挂起
使用vTaskSuspend()函数即可,参数只有一个:想要挂起任务的句柄。
恢复
使用vTaskResume()函数即可,参数只有一个:想要恢复任务的句柄。
删除
使用vTaskDelete()函数即可,参数只有一个:想要删除任务的句柄。

printf("挂起LED\r\n");vTaskSuspend(LED_TaskHandle);//挂起 printf("继续LED\r\n");vTaskResume(LED_TaskHandle);//继续 printf("删除LED\r\n");vTaskDelete(LED_TaskHandle);//删除 

四、需求实现代码

在该系统中实现任务的创建、挂起、恢复和删除

#include "stm32f10x.h" #include "led.h" #include "delay.h" //使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h" #include "FreeRtos.h" #include "task.h" #include "usart.h" #include "key.h" TaskHandle_t LED_TaskHandle;//LED TaskHandle_t KEY_TaskHandle;//KEY   void Led_Task(void *p) { 	uint8_t i=0; 	while(1) 	{ 		i++; 		printf("i=%d\r\n",i); 		Led_Toggle(1); 		Delay_nms(300); 	} }  void KEY_Task(void *p) { 	while(1) 	{ 		switch(key_getvalue()) 		{ 			case 1:{printf("挂起LED\r\n");vTaskSuspend(LED_TaskHandle);}break;//挂起 			case 2:{printf("继续LED\r\n");vTaskResume(LED_TaskHandle);}break;//继续 			case 3:{printf("删除LED\r\n");vTaskDelete(LED_TaskHandle);}break; 			case 4:{	BaseType_t Ret = pdPASS;	 								Ret = xTaskCreate(  Led_Task, "LED1_toggle",50,NULL,2,&LED_TaskHandle); 								if(Ret==pdPASS) 								{ 									printf("LED_Task创建成功!\r\n"); 								} 						 };break; 		} 		vTaskDelay(10); 	} }   int main() { 	Led_Init(); 	key_Init(); 	Usart1_Config(); 	BaseType_t Ret = pdPASS; 	Ret = xTaskCreate(  Led_Task,                        "LED1_toggle",                         50,//栈深度,32位单片机*4                         NULL, 												2,                         &LED_TaskHandle                      ); 	if(Ret==pdPASS) 	{ 		printf("LED_Task创建成功!\r\n"); 	} 	Ret = xTaskCreate(  KEY_Task,                        "KEY_Task",                         80,//栈深度,32位单片机*4                         NULL, 												2,                         &KEY_TaskHandle                      ); 	if(Ret==pdPASS) 	{ 		printf("KEY_Task创建成功\r\n"); 	} 	printf("开始调度!\r\n"); 	vTaskStartScheduler(); 	while(1) 	{ 		 	} }  

将之前写的传感器模块的数据获取,移植到FreeRtos(嵌入式实时操作系统)环境下
main.c

#include "stm32f10x.h" #include "led.h" #include "delay.h" #include "delay.h" #include "string.h" #include "pwm.h" #include "adc.h" #include "su03t.h" #include "dht11.h" #include "kqm.h"  //使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h" #include "FreeRtos.h" #include "task.h" #include "usart.h" #include "key.h" TaskHandle_t Deal_TaskHandle;//数据处理  void Data_Task(void *p) { 	while(1) 	{ 	Get_Smoke_Light_MidValue(); 	DHT11_ReadData(); 	Delay_nms(300); 	KQM_DealData(); 	Su03tDealData(); 	} }  int main() { 	RGBpwm_Config();  	Kqm_U4Config();  	Su03t_U5Config(); 	DHT11_Config();	  	Adc_Config(); 	Led_Init(); 	key_Init(); 	Usart1_Config(); 	BaseType_t Ret = pdPASS; 	Ret = xTaskCreate(  Data_Task,                        "DealData",                         100,//栈深度,32位单片机*4                         NULL, 												2,                         &Deal_TaskHandle                      ); 	if(Ret==pdPASS) 	{ 		printf("语音创建成功!\r\n"); 	} 	printf("开始调度!\r\n"); 	vTaskStartScheduler(); 	while(1) 	{ 		 	} }  

相关内容

热门资讯

今年以来!91y游戏辅助透视挂... 今年以来!91y游戏辅助透视挂,福城麻将是有挂,一贯竟然有挂1、首先打开91y游戏辅助器下载最新版本...
据报道!一发棋牌辅助透视挂,喜... 据报道!一发棋牌辅助透视挂,喜乐会真的有挂,一贯发现有挂1、用户打开应用后不用登录就可以直接使用,点...
据文件显示!酷玩部落辅助透视挂... 据文件显示!酷玩部落辅助透视挂,呼包鄂游戏真的是有挂,本来有挂助手1、让任何用户在无需酷玩部落安装教...
据玩家消息!微乐刨幺辅助透视挂... 据玩家消息!微乐刨幺辅助透视挂,云南山水麻将真的是有挂,其实讲解有挂微乐刨幺破解侠是真的助透视。每个...
截至发稿!欢乐龙城3辅助透视挂... 截至发稿!欢乐龙城3辅助透视挂,铃铛游戏3D真的有挂,总是有挂助手铃铛游戏3D透视方法中分为三种模型...
相较于以往!中至鹰潭麻将辅助透... 相较于以往!中至鹰潭麻将辅助透视挂,赤峰麻将确实有挂,一直有挂分析中至鹰潭麻将脚本下载中分为三种模型...
据监测!极美辅助透视挂,大神罗... 据监测!极美辅助透视挂,大神罗山麻将存在有挂,其实有挂神器暗藏猫腻,小编详细说明极美破解器有用吗(w...
2026版总结!开心玩辅助透视... 2026版总结!开心玩辅助透视挂,九五确实有挂,好像有挂方法1、每一步都需要思考,不同水平的挑战会更...
现就发布提示!518互娱辅助透... 现就发布提示!518互娱辅助透视挂,天天石城麻将存在有挂,总是有挂详细1、进入到518互娱是否有挂之...
目前!丁二红辅助透视挂,微乐碰... 目前!丁二红辅助透视挂,微乐碰胡确实有挂,竟然有挂分析该软件可以轻松地帮助玩家将丁二红外卦神器提升到...