STM32第十九课:FreeRTOS移植和使用

2024-07-21 1481阅读

目录

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

        需求

        1.将FreeRtos(嵌入式实时操作系统)移植到STM32中。

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

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

        STM32第十九课:FreeRTOS移植和使用

        STM32第十九课:FreeRTOS移植和使用


        一、FreeRtos概要

        STM32裸机运行代码:

        STM32第十九课:FreeRTOS移植和使用

        加入FreeRtos后:

        STM32第十九课:FreeRTOS移植和使用

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

        STM32第十九课:FreeRTOS移植和使用

        二、移植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.复制源码

        先打开移植的文件夹:

        STM32第十九课:FreeRTOS移植和使用

        将源码直接复制到想要移植的工程文件下,改名为FreeRtos:

        STM32第十九课:FreeRTOS移植和使用

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

        STM32第十九课:FreeRTOS移植和使用

        在portable文件夹中找到MemMang文件夹,该文件夹放着的就是内存分配文件,我们选择4就行。

        STM32第十九课:FreeRTOS移植和使用

        port,就是内核相关的接口文件,是必要添加的。

        3.FreeRTOSConfig.h

        STM32第十九课:FreeRTOS移植和使用

        打开样例文件夹,找到相对应的芯片,将FReeRTOSconfig.h文件复制过来即可。

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

        .c

        STM32第十九课:FreeRTOS移植和使用

        .h

        STM32第十九课:FreeRTOS移植和使用

        其中,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)
        	{
        		
        	}
        }
        
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]