STM32F1+HAL库+FreeTOTS学习3——任务创建(动态和静态两种)

STM32F1+HAL库+FreeTOTS学习3——任务创建(动态和静态两种)

  • 任务创建API函数
  • 任务创建流程
  • 代码实现
    • 1. 动态任务创建和删除
    • 2. 静态任务创建和删除

上期我们学习了STM32移植FreeRTOS搭建基准工程,现在我们来学习任务创建

任务创建API函数

前面我们了解到,FreeRTOS相对于裸机开发,最大的不同在与支持多任务同时运行,那么FreeRTOS上运行多少个任务,任务运行的优先级、堆栈大小,这些都是怎么确定?当然是我们自己去创建任务,自己确定。。。。。。。

FreeRTOS的任务创建删除本质就是调用FreeRTOS的API函数,分为动态创建和静态创建两种:

  • 动态创建的任务,由FreeRTOS自己从管理的堆栈中分配,用户只需要确定堆栈大小即可。
  • 静态创建的任务,由用户自己定义堆栈,将定义好的堆栈分配给任务。这部分堆栈由用户控制和管理,不受FreeRTOS的管控。

具体API函数如下:

  1. 动态创建任务函数
BaseType_t xTaskCreate
( 	TaskFunction_t 				pxTaskCode,		/* 指向任务函数的指针 */					const char * const 				pcName, 		/* 任务名字,最大长度configMAX_TASK_NAME_LEN */
	const 	configSTACK_DEPTH_TYPE 		usStackDepth, 	/* 任务堆栈大小,注意字为单位 */
	void * const 					pvParameters,	/* 传递给任务函数的参数 */
	UBaseType_t 					uxPriority,		/* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1 */
	TaskHandle_t * const 			pxCreatedTask 	/* 任务句柄,就是任务的任务控制块 */
);

/*
返回值为:pdPASS ,表示创建成功
返回值为:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY,表示创建失败
*/
  1. 静态创建任务
TaskHandle_t xTaskCreateStatic
(
    	TaskFunction_t		pxTaskCode,				/* 指向任务函数的指针 */
    	const char * const		pcName,				/* 任务函数名 */
    	const uint32_t			ulStackDepth, 			/* 任务堆栈大小注意字为单位 */
    	void * const			pvParameters, 			/* 传递的任务函数参数 */
    	UBaseType_t			uxPriority, 				/* 任务优先级 */
    	StackType_t * const		puxStackBuffer, 			/* 任务堆栈,一般为数组,由用户分配 */
    	StaticTask_t * const		pxTaskBuffer				/* 任务控制块指针,由用户分配 */
); 

/*
返回值为NULL:表示任务创建失败
返回值为其他值:任务句柄,任务创建成功
*/
  1. 任务删除函数
  • 被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除。
  • 当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)
  • 空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄露
void vTaskDelete(TaskHandle_t xTaskToDelete);

/*
参数为待删除任务的句柄,用于删除已
*/

任务创建流程

动态创建任务函数创建流程:

  1. 将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1
  2. 定义函数入口参数
  3. 编写任务函数
  4. 完成以上三个步骤即可完成一个任务的动态创建,任务创建完毕后任务会立刻进入就绪状态,由任务调度器控制并运行,内部实现方法如下:

在这里插入图片描述
在这里插入图片描述

静态创建任务使用流程

  1. 需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1
  2. 定义空闲任务&定时器任务的任务堆栈及TCB
  3. 实现两个接口函数:vApplicationGetIdleTaskMemory( ) 和vApplicationGetTimerTaskMemory ( )
  4. 定义函数入口参数
  5. 编写任务函数
  6. 任务创建完毕后任务会立刻进入就绪状态,由任务调度器控制并运行,内部实现方法如下:
    在这里插入图片描述

删除任务流程

  1. 使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1
  2. 入口参数输入需要删除的任务句柄(NULL代表删除本身)
  3. 内部实现方式如下:
    在这里插入图片描述

代码实现

1. 动态任务创建和删除

  1. 在main.c中调用如下函数,进入FreeRTOS操作系统。
	freertos_demo();
  1. 在freertos_demo.c里面编写动态任务创建,并编写任务功能函数


#include "freertos_demo.h"
#include "main.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 */

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 */

/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 */

/******************************************************************************************************/

/* LCD刷屏时使用的颜色 */


/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{

    
    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();		//开启任务调度
}

/**
 * @brief       start_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区,关闭中断,此时停止任务调度*/
    /* 创建任务1 */
    xTaskCreate((TaskFunction_t )task1,
                (const char*    )"task1",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);
    /* 创建任务2 */
    xTaskCreate((TaskFunction_t )task2,
                (const char*    )"task2",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区,重新开启中断,开启任务调度 */
}

/**
 * @brief       task1
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task1(void *pvParameters)
{
    
    while(1)
    {
        HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);  
		 printf("task1 start\r\n");
		 /* LED0闪烁 */
        vTaskDelay(1000);                                               /* 延时1000ticks */
    }
}

/**
 * @brief       task2
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task2(void *pvParameters)
{
    float float_num = 0.0;
    
    while(1)
    {
        float_num += 0.01f;                         /* 更新数值 */
        printf("float_num: %0.4f\r\n", float_num);  /* 打印数值 */
		 printf("task2 start\r\n");
        vTaskDelay(1000);                           /* 延时1000ticks */
    }
}

2. 静态任务创建和删除

  1. 动态任务创建
    在main.c中调用如下函数,进入FreeRTOS操作系统。
	freertos_demo();
  1. 在freertos_demo.c里面编写静态任务创建,并编写任务功能函数


#include "freertos_demo.h"
#include "main.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO 1                  				 /* 任务优先级 */
#define START_STK_SIZE  128                				 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler; 				 /* 任务句柄 */
StackType_t   StartTask_Stack[START_STK_SIZE];	 /*任务堆栈*/
StaticTask_t   StartTask_TCB;  						/*任务控制块*/
void start_task(void *pvParameters);       				 /* 任务函数 */

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
StackType_t   Task1_Stack[TASK1_STK_SIZE];	 /*任务堆栈*/
StaticTask_t   Task1_TCB;  						/*任务控制块*/
void task1(void *pvParameters);             /* 任务函数 */

/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
StackType_t   Task2_Stack[TASK2_STK_SIZE];	 /*任务堆栈*/
StaticTask_t   Task2_TCB;  						/*任务控制块*/
void task2(void *pvParameters);             /* 任务函数 */

/******************************************************************************************************/

/* 空闲任务内存分配*/
StaticTask_t idle_task_tcb;
StackType_t  idle_task_stack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,  //任务控制块内存
											 StackType_t  ** ppxIdleTaskStackBuffer,
											 uint32_t * pulIdleTaskStackSize ) /*lint !e526 Symbol not defined as it is an application callback. */
{
	* ppxIdleTaskTCBBuffer = &idle_task_tcb;
	* ppxIdleTaskStackBuffer = idle_task_stack;
	* pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/* 软件定时器内存分配*/
StaticTask_t timer_task_tcb;
StackType_t  timer_task_stack[configTIMER_TASK_STACK_DEPTH];
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
											  StackType_t ** ppxTimerTaskStackBuffer,
											  uint32_t * pulTimerTaskStackSize )
{
	* ppxTimerTaskTCBBuffer = &timer_task_tcb;
	* ppxTimerTaskStackBuffer = timer_task_stack;
	* pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}


/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */

void freertos_demo(void)
{
	//静态创建任务函数,返回值为任务句柄
	
	StartTask_Handler = xTaskCreateStatic( (TaskFunction_t) start_task,	//指向任务函数的指针
                                    (const char * const)"start_task", 			//任务函数名
                                    (const uint32_t) START_STK_SIZE,		//任务堆栈大小,单位为字节
                                    (void * const) NULL,					//传递的任务函数参数
                                    (UBaseType_t) START_TASK_PRIO,		//任务优先级
                                    (StackType_t * const) StartTask_Stack,		//任务堆栈,一般为数组,用户自己分配
                                    (StaticTask_t * const) &StartTask_TCB );		//任务控制块指针,由用户分配				
    vTaskStartScheduler();		//开启任务调度
												
}

/**
 * @brief       start_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区,关闭中断,此时停止任务调度*/
    /* 创建任务1,静态的方式 */
	Task1Task_Handler = xTaskCreateStatic( (TaskFunction_t			) task1,		//指向任务函数的指针
														( char * 	) "task1", 	//任务函数名
														( uint32_t		) TASK1_STK_SIZE,	//任务堆栈大小,单位为字节
														(void * 			) NULL,	//传递的任务函数参数
														(UBaseType_t			) TASK1_PRIO,			//任务优先级
														(StackType_t * 	) Task1_Stack,	//任务堆栈,一般为数组,用户自己分配
														(StaticTask_t * ) &Task1_TCB );	//任务控制块指针,由用户分配
														    /* 创建任务2,静态的方式 */
	Task2Task_Handler = xTaskCreateStatic( (TaskFunction_t			) task2,		//指向任务函数的指针
														( char * 	) "task2", 	//任务函数名
														( uint32_t		) TASK2_STK_SIZE,	//任务堆栈大小,单位为字节
														(void * 			) NULL,	//传递的任务函数参数
														(UBaseType_t			) TASK2_PRIO,			//任务优先级
														(StackType_t * 	) Task2_Stack,	//任务堆栈,一般为数组,用户自己分配
														(StaticTask_t * ) &Task2_TCB );	//任务控制块指针,由用户分配
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区,重新开启中断,开启任务调度 */
}

/**
 * @brief       task1
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task1(void *pvParameters)
{
    
    while(1)
    {
        HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);  
		 printf("task1 start\r\n");
		 /* LED0闪烁 */
        vTaskDelay(1000);                                               /* 延时1000ticks */
    }
}

/**
 * @brief       task2
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void task2(void *pvParameters)
{
    float float_num = 0.0;
    
    while(1)
    {
        float_num += 0.01f;                         /* 更新数值 */
        printf("float_num: %0.4f\r\n", float_num);  /* 打印数值 */
		 printf("task2 start\r\n");
        vTaskDelay(1000);                           /* 延时1000ticks */
    }
}

静态实现和动态实现的代码作用是一样的,这里统一解释以下:

  1. 创建了一个开始任务,在开始任务中创建任务1和任务2,创建完成后删除开始任务。
  2. 任务1执行LED闪烁,周期为1S
  3. 任务2执行串口打印,每一秒打一次信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/766065.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大数据可视化实验(八):大数据可视化综合实训

目录 一、实验目的... 1 二、实验环境... 1 三、实验内容... 1 1)Python纵向柱状图实训... 1 2)Python水平柱状图实训... 3 3)Python多数据并列柱状图实训.. 3 4)Python折线图实训... 4 5)Python直方图实训...…

Redis---保证主从节点一致性问题 +与数据库数据保持一致性问题

保证主从节点一致性问题 Redis的同步方式默认是异步的,这种异步的同步方式导致了主从之间的数据存在一定的延迟,因此Redis默认是弱一致性的。 解决: 1.使用Redisson这样的工具,它提供了分布式锁的实现,确保在分布式环…

搭贝这个低代码开发平台靠谱吗?

在应用开发领域,低代码开发平台因其拖拽式的操作给用户带来了极大的便利和灵活性。根据相关调查数据,2022年国内低代码开发平台已超过100家。搭贝在众多低代码平台中也享有一定的知名度。那么,搭贝究竟怎么样,是否值得信赖&#x…

Dify入门指南

一.Dify介绍 生成式 AI 应用创新引擎,开源的 LLM 应用开发平台。提供从 Agent 构建到 AI workflow 编排、RAG 检索、模型管理等能力,轻松构建和运营生成式 AI 原生应用,比 LangChain 更易用。一个平台,接入全球大型语言模型。不同…

IDEA Debug 断点

今天在工作发现有些新入职的小伙伴们,在调试程序时不是很会正确使用IDEA所提供Breakpoints(断点),这里就简单的介绍下比较常用的功能。 快捷键: 切换行断点:Ctrl F8 编辑断点属性:Ctrl Shift F8 断点的类型 行断点&am…

Google地图获取位置的前端代码与测试

test.html <script src"http://maps.google.com/maps/api/js?sensorfalse"></script> <script > if (navigator.geolocation) {  console.log(Geolocation is supported!);// var startPos;var geoSuccess function(position) {startPos p…

Codeforces Round 954 (Div. 3)(A~E)

目录 A. X Axis B. Matrix Stabilization C. Update Queries D. Mathematical Problem A. X Axis Problem - A - Codeforces 直接找到第二大的数&#xff0c;答案就是这个数与其他两个数的差值的和。 void solve() {vector<ll>a;for (int i 1; i < 3; i){int x;…

【C++知识点总结全系列 (02)】:C++中的语句、运算符和表达式详细总结

文章目录 1、语句(1)简单语句A.空语句B.复合语句 (2)条件语句(3)迭代语句A.常规for循环B.范围for循环C.while和do...while (4)跳转语句A.break语句B.continue语句C.goto语句 (5)异常处理语句A.标准异常B.throw抛出异常 (6)try语句 2、运算符(1)算术运算符(2)关系运算符(3)逻辑运…

Java Character类

Character是char的包装类 转义序列 Character类的方法

SpringSecurity中文文档(Servlet Persisting Authentication)

Persisting Authentication 用户第一次请求受保护的资源时&#xff0c;系统会提示他们输入凭据。提示凭据的最常见方法之一是将用户重定向到登录页。对于请求受保护资源的未经身份验证的用户&#xff0c;总结的 HTTP 交换可能如下所示: Example 1. Unauthenticated User Requ…

机器人控制系列教程之Simulink中模型搭建(1)

机器人模型获取 接上期&#xff1a;机器人控制系列教程之控制理论概述&#xff0c;文中详细讲解了如何通过Solidworks软件导出URDF格式的文件。文末提到了若需要将其导入到Simulink中可在命令行中输入smimport(urdf/S_Robot_urdf.urdf)&#xff0c;MATLAB将自动打开Simulink以…

【揭秘】国内十大顶尖AI大模型,引领智能科技新纪元

大模型大模型通常指的是参数量非常大、数据量也非常大的深度学习模型。这些模型由数百万到数十亿甚至更多的参数组成&#xff0c;需要海量的数据和强大的计算资源进行训练和推理学习的模型。大模型设计的目的在于提高模型的表示能力和性能、应对复杂数据集和任务、提升泛化能力…

65.WEB渗透测试-信息收集- WAF、框架组件识别(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;64.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;4&#xff09;-CSDN博客 waf绕…

c语言的烫烫烫烫烫??

当初学习C语言时&#xff0c;对于一些特殊的打印输出可能会感到困惑&#xff0c;比如会出现一堆乱码烫烫烫的情况。其实这是因为在C语言中&#xff0c;对于字符类型和数字类型之间的隐式转换可能会导致打印输出的结果不符合预期。这并不意味着程序员"烫"&#xff0c;…

详解归一化、标准化、正则化以及batch normalization

文章目录 what(是什么)where&#xff08;用在哪&#xff09;How&#xff08;如何用&&原理&#xff09;归一化实现方式原理示例说明 标准化实现方式原理示例说明 正则化实现方式原理作用 Batch Normalizationpytorch中的batch normalization原理BN的作用 归一化、标准化…

EXCEL怎么一模一样复制粘贴?

第一步 鼠标选中复制子表 右击建立副本 第二步 建立好副本表格 第三步 将选定工作表移动至新表格 第四步 成功完成移动

社区的用户分层运营如何做?

在社区运营中用户分层尤为关键&#xff0c;20%的高粘性用户带动80%的普通用户。我们主要围绕的是这20%的粘性用户&#xff0c;因为他们才是决定我们未来能不能最好做大最重要的人 分层运营策略 1️⃣对普通用户&#xff1a; &#x1f4da;满意&#xff1a;搜索是内容多而全&…

数据结构 -AVL树

文章目录 AVL树左旋和右旋插入的四种情况&#xff08;一&#xff09;新数字插到了左子树&#xff0c;导致左子树比右子树高2&#xff1b;左孩子的左子树比其右子树高1&#xff08;二&#xff09;新数字插到了左子树&#xff0c;导致左子树比右子树高2&#xff1b;左孩子的右子树…

linux的Top学习

学习文档 https://www.cnblogs.com/liulianzhen99/articles/17638178.html TOP 问题 1&#xff1a;top 输出的利用率信息是如何计算出来的&#xff0c;它精确吗&#xff1f; top 命令访问 /proc/stat 获取各项 cpu 利用率使用值内核调用 stat_open 函数来处理对 /proc/sta…

蓝桥杯算法双周赛

四、赛后真题解析 比赛赛后将提供免费直播讲解&#xff0c;主讲人&#xff1a;待定。时间&#xff1a;07 月 13 日&#xff08;比赛当日&#xff09;晚 21 时。观看直播地址&#xff1a;第3场蓝桥算法季度赛赛后题解直播 - 蓝桥云课 - 哔哩哔哩直播&#xff0c;二次元弹幕直播…
最新文章