【复习笔记】FreeRTOS(二)创建和删除任务

news2024/11/23 7:23:50

本文是FreeRTOS复习笔记的第二节,创建和删除任务,使用的开发板是stm32f407VET6,创建两个任务,task1负责闪烁LED,task2负责按键控制,当按键按下时task1停止执行,任务的状态显示到TFT显示屏和串口上。

上一篇文章:【复习笔记】FreeRTOS(一)

文章目录

  • 一、实验目的
  • 二、测试例程
  • 三、实验效果


一、实验目的

本节的学习目的学习FreeRTOS创建任务和删除任务,任务创建和删除本质就是调用FreeRTOS的API函数。
任务创建和删除主要用到3个API函数:

函数作用
xTaskCreate()使用动态的方法创建一个任务。所需的内存均由FreeRTOS从FreeRTOS管理的堆中分配,不需要人为操作
xTaskCreateStatic()使用静态的方法创建一个任务,任务的任务控制块以及任务的栈空间所需的内存需要用户分配提供
xTaskCreateRestricted()创建一个使用MPU任务进行限制的任务 ,相关内存使用动态内存分配
vTaskDelete()删除一个任务

这里主要比较一下动态创建任务和静态创建任务
动态创建任务函数包含了6个参数:

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

pxTaskCode: 指向任务函数的指针。比如创建了一个任务,任务所需要实现的功能全部放在任务函数中,通过此参数指向任务函数。

pcName: 任务名字。名字长度由FreeRTOSConfig.h中的宏configMAX_TASK_NAME_LEN决定,默认为16字符长度。

usStackDepth: 任务堆栈大小。注意单位是“字”。例如堆大小为100,则实际大小为100×4=400字节。

pvParameters: 传递给任务函数的参数。一般用不到,传入空(NULL)。

uxPriority: 任务优先级。每个任务都有自己的优先级,具体范围是0~configMAX_PRIORITIES - 1,宏定义在FreeRTOSConfig中设置。在程序中设置的为32,并且任务优先级越大,任务就越优先。

pxCreatedTask: 任务句柄。删除任务是通过任务句柄进行操作,任务句柄其实就是任务的任务控制块。在函数内部任务控制块等效于任务句柄。

静态创建任务函数包含了7个参数:

TaskHandle_t xTaskCreateStatic
(
    	TaskFunction_t		    pxTaskCode,			/* 1.指向任务函数的指针 */
    	const char * const		pcName,				/* 2.任务函数名 */
    	const uint32_t			ulStackDepth, 		/* 3.任务堆栈大小注意字为单位 */
    	void * const			pvParameters, 		/* 4.传递的任务函数参数 */
    	UBaseType_t			    uxPriority, 		/* 5.任务优先级 */
    	StackType_t * const		puxStackBuffer, 	/* 6.任务堆栈,一般为数组,由用户分配 */
    	StaticTask_t * const	pxTaskBuffer	    /* 7.任务控制块指针,由用户分配 */
); 	

它和动态创建任务的区别主要是后两个参数
puxStackBuffer: 任务堆栈。一般为数组,由用户自己定义(这里和动态创建有区别,动态创建只需要指定任务堆栈大小ulStackDepth,剩下的是由FreeRTOS根据任务大小,自动去申请堆大小,而静态需要给定数组地址)。

pxTaskBuffer: 任务控制块指针。指向任务控制块的地址,任务控制块保留了很对信息,信息需要内存来保存,这部分内存也需要用户自己分配。

然后讲一下任务删除函数:

void vTaskDelete(TaskHandle_t xTaskToDelete);

任务删除函数只有一个入口参数 xTaskToDelete:待删除任务的任务句柄。此函数用于删除已经被创建成功的任务,如果没有被创建,是不能被删除的。被删除的任务将从就绪态任务列表、阻塞态任务列表、 挂起态任务列表和事件列表中移除。

当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)。比如说创建了两个任务task1、task2,在task1的任务函数中调用的任务删除,传入的参数为task2的任务句柄,则删除task2这个任务,如果传入NULL参数,则删除自身task1任务。空闲任务会负责释放被删除任务中被系统分配的内存。删除自身任务,即函数xTaskDelete()传入NULL时,才会利用空闲任务释放掉被删除任务使用的系统分配的内存,如果是在task1任务中删除task2,则在task1中释放task2所使用的内存空间。

本实验使用的开发板是stm32f407VET6最小系统板,搭载1.44寸TFT。使用动态创建任务的方法创建两个任务,task1负责闪烁LED,task2负责按键控制,当按键按下时task1停止执行,任务的状态显示到TFT显示屏和串口上。
在这里插入图片描述

二、测试例程

程序上主要用到xTaskCreate()函数,使用动态的方法创建任务,以及使用vTaskDelete()删除任务。程序上主要是创建两个任务,task1负责闪烁LED,task2负责按键控制,当按键按下时删除任务task1,任务的状态显示到TFT显示屏和串口上。
主函数 main.c代码如下:


#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "key.h"
#include "GUI.h"
#include "Lcd_Driver.h"
#include "TFT_demo.h"
#include "FreeRTOS.h"
#include "task.h"

#define START_TASK_PRIO		1 //任务优先级	
#define START_STK_SIZE 		128  //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void *pvParameters); //任务函数

#define TASK1_TASK_PRIO		2 //任务优先级
#define TASK1_STK_SIZE 		128  //任务堆栈大小	
TaskHandle_t TASK1Task_Handler; //任务句柄
void task1_task(void *p_arg); //任务函数

#define TASK2_TASK_PRIO		3 //任务优先级
#define TASK2_STK_SIZE 		128  //任务堆栈大小	
TaskHandle_t TASK2Task_Handler; //任务句柄
void task2_task(void *p_arg); //任务函数

int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
	delay_init(168);		//初始化延时函数
	uart_init(115200);     	//初始化串口
	LED_Init();		        //初始化LED端口
	KEY_Init();
	Lcd_Init();	 //1.44寸液晶屏--初始化配置
	Lcd_Clear(GRAY0);//清屏
	//创建开始任务
    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  开始任务任务函数
  * @param  None
  * @retval None  
  */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区

    xTaskCreate((TaskFunction_t )task1_task,     
                (const char*    )"task1_task",   
                (uint16_t       )TASK1_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK1_TASK_PRIO,
                (TaskHandle_t*  )&TASK1Task_Handler);  

	xTaskCreate((TaskFunction_t )task2_task,     
                (const char*    )"task2_task",   
                (uint16_t       )TASK2_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&TASK2Task_Handler);  
				
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


/**
  * @brief  显示任务1运行,而且LED 0.5s闪烁
  * @param  None
  * @retval None  
  */
void task1_task(void *pvParameters)
{
	Lcd_Clear(GRAY0);

	while(1)
	{
		printf("任务1运行中\r\n");
		Gui_DrawFont_GBK16(6,8,BLUE,BLUE,"task1:runing");
		LED0=~LED0;
        vTaskDelay(500);
    }
	
}	
 
/**
  * @brief  按键按下就删除任务1的执行程序,led停止闪烁
  * @param  None
  * @retval None  
  */
void task2_task(void *pvParameters)
{

	u8 key1;
	Lcd_Clear(GRAY0);
	while(1)
	{
		   key1=KEY_Scan(0);
		if(key1==WKUP_PRES)
		{
            vTaskDelete(TASK1Task_Handler);//任务2删除任务1
			printf("任务1删除了任务2!\r\n");
    	    Gui_DrawFont_GBK16(6,8,BLUE,GRAY0,"task1:stopping");
			Gui_DrawFont_GBK16(0,38,RED,GRAY0,"task2 Delete 1");
		}
		vTaskDelay(500);    
    }
}

按键驱动函数,key.c

#include "key.h"
#include "delay.h" 

/**
  * @brief  按键初始化函数,设置PA0为按键接口,按下就通过电阻接3.3上拉
  * @param  None
  * @retval None  
  */
void KEY_Init(void)
{
	
	GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA,时钟 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//WK_UP对应引脚PA0--K1按键
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;//下拉
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0
 
} 

/**
  * @brief  按键处理函数,返回按键值
  * @param  mode:0,不支持连续按;1,支持连续按;
  * @retval 0,没有任何按键按下
  * @retval 1,WKUP按下 --对应K1按键
  */
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		  
	if(key_up&&(WK_UP==1))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(WK_UP==1) return WKUP_PRES;
	}
	else if(WK_UP==0)key_up=1; 	    
 	return 0;// 无按键按下
}

三、实验效果

实验效果如下:

在这里插入图片描述

首先是TFT显示屏上显示“task1:running1”,并且LED引脚电平500ms改变一次,一闪一闪的。当按下按键时,LED停止闪烁,显示屏显示“task1:stopping”下行显示“task2 Delete task1”。如果接上串口,就能看到提示内容。

好了,本节主要是学习和掌握任务创建以及 vTaskDelete() 任务删除函数的使用。
完整程序放在gitee上:程序下载地址

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据库系统及应用】— 日志、故障恢复、事务、并发控制、调度、检查点

日志文件是用于记录__________。 A、数据操作 B、程序运行过程 C、程序执行结果 D、对数据的所有更新操作 下列说法正确的是__________。 A、事务故障可以通过运行日志进行恢复 B、介质故障只需将备份恢复到系统中即可实现正确性 C、检查点是指检查发生故障并进行恢复的时刻点…

MySQL 对日期使用 DATE_FORMAT()函数

文章目录 DATE_FORMAT()函数显示今天是星期几只显示年月显示当前时间的分钟数和秒数 DATE_FORMAT()函数 前面使用日期时间函数,获取到的要么是 yyyy-mm-dd 形式的日期,要么是 hh:MM:ss 形式的时间,或者是 yyyy-mm-dd hh:mm:ss 形式的日期及时…

论文解读 | ICRA2022:用深度贝叶斯算法来估计ICP的协方差

原创 | 文 BFT机器人 01 研究背景 在点云处理中,ICP算法是一种常用的点云配准方法,通过将两个或多个点云对齐,可以进行后续的建模、识别和跟踪等处理。 然而,在ICP算法中,协方差估计起着非常重要的作用,它…

网络安全基础免杀

1. 会话提升的几种方式2. armitage的熟悉3. handler生成监听器的方法4. 防止会话假死5. 控制台设置编码6. upx加壳7. msfvenom木马payload持久化8. msfvenom木马编码 正文 免杀1 1. 会话提升的几种方式 python -c "import pty;pty.spawn(/bin/bash);" 会话提升 se…

linuxOps基础_linux文件打包压缩与解压缩

linux打包压缩概念 默认情况下,Linux的压缩概念一次只能压缩一个文件。针对多文件或文件夹无法进行直接压缩。所以需要提前对多个文件或文件夹进行打包,这样才可以进行压缩操作。 打包 1.txt 5MB 2.txt 10MB 3.txt 15MB1.txt 2.txt 3.txt 打包…

为kong网关添加key-auth插件实现安全认证

官方指导文档:https://docs.konghq.com/gateway/latest/get-started/key-authentication/ 一、新建一个用户 这里我们新建一个usernameluka的用户 [rootmin ~]# curl -i -X POST http://localhost:8001/consumers/ \ > --data usernameluka HTTP/1.1 201 Cr…

JavaEE HTTP状态码 HTTP数据报的构造

HTTP状态码HTTP数据报的构造 文章目录 JavaEE & HTTP状态码 & HTTP数据报的构造1. HTTP状态码1.1 200 - OK1.2 404 - Not Found1.3 403 - Forbidden1.4 500 - Internal Server Error1.5 504 - Gateway Timeout1.6 302/301 重定向 2. 构造HTTP请求2.1 浏览器搜索栏输入u…

聚焦2023北京安博会,超高清安防应用将成潮流

(1)2023北京安博会 中国安全防范产品行业协会主办并承办的第十六届(2023)中国国际社会公共安全产品博览会(Security China 2023),将于2023年6月7~10日在北京首钢会展中心开幕。安博…

面试阿里测开岗失败后,被面试官在朋友圈吐槽了......

前一阵子有个徒弟向我诉苦,说自己在参加某大厂测试面试的时候被面试官怼得哑口无言,场面让他一度十分尴尬 印象最深的就是下面几个问题: 根据你以前的工作经验和学习到的测试技术,说说你对质量保证的理解? 非关系型…

Jenkins+JMeter实现自动化,性能压测玩转CICD!

目录 前言: 准备工作 编写Jenkinsfile 编写JMeter脚本 编写 Dockerfile 总结 前言: 性能压测是应用程序开发中不可或缺的一环。它通过模拟应用程序在真实环境下的负载情况,从而检测系统在高负载下的性能表现。而随着依托云架构部署业务的不…

2022年长三角高校数学建模竞赛B题齿轮箱故障诊断解题全过程文档及程序

2022年长三角高校数学建模竞赛 B题 齿轮箱故障诊断 原题再现: 齿轮箱是用于增加输出扭矩或改变电机速度的机械装置,被广泛应用于如汽车、输送机、风机等机械设备中。它由两个或多个齿轮组成,其中一个齿轮由电机驱动。电机的轴连接到齿轮箱的…

大数据 Ranger2.1.0 适配 Kafka3.4.0

Ranger2.1.0 适配 Kafka3.4.0 官方说明POM代码说明 根据官方说明Kafka3.0以上版本将会被替换权限认证方式,包括 类和方法 的变换,所以需要对ranger中继承 kafka 的实现中,修改相应的逻辑 官方说明 Kafka3.0以上版本将会被替换权限认证方式&a…

vue项目瘦身

如图 项目中node_modules包已占用十几G,我也是发现我的磁盘空间缩小的超级快,因为好几个项目,甚至有的项目包已经占了50多G,这都得益于上一个刚走了的laji npm install -g depcheck 一旦安装了depCheck,您可以在命令行…

通过 Github workflows CI/CD 自动化部署 Github Pages hugo 免费博客

通过 Github workflows CI/CD 自动化部署 Github Pages hugo 免费博客 文章博客地址:https://blog.taoluyuan.com/posts/github-workflows/ Github Workflows 介绍 GitHub Actions 介绍 GitHub 文档:https://docs.github.com/zh/actions/learn-githu…

相机的畸变矫正与opencv代码说明

相机的畸变矫正与opencv代码说明 简介鱼眼模型的畸变校正针孔模型的畸变校正 简介 图像算法中会经常用到摄像机的畸变校正,有必要总结分析OpenCV中畸变校正方法,其中包括普通针孔相机模型和鱼眼相机模型fisheye两种畸变校正方法。普通相机模型畸变校正函…

机器人专业讲师与科技的转型思考

2023年以前,编程需要学习各种语法,现在只需要提示词。 未来还需要编程老师吗?需求一定越来越少。 “ Prompting TurtleSim from ChatGPT ” https://github.com/mhubii/chatgpt_turtlesim The demo lets ChatGPT call into ROS services …

左孩子右兄弟路径之谜

题目 对于一棵多叉树,我们可以通过 “左孩子右兄弟” 表示法,将其转化成一棵二叉树。 如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。 换句话说,每个结点可以选任意子结点作为左孩子,并按任意顺序…

开源版社区团购系统源码 含小程序完整前后端+搭建教程+私有化部署

分享一个社区团购系统源码,源码开源可自由二开,含小程序完整前后端和详细的搭建教程,可私有化部署终身使用,功能界面diy团长供应商拼团秒杀优惠券菜谱积分群接龙充值预售配送等功能。 系统功能一览: 1、商品&#xf…

企业级应用:检测服务是否正常运行

1.说明: 在公司日常小项目中,会遇到一些小需求,比如:检测服务是否正常运行。 当一个经验不是很足的项目经理,让你写一个接口,然后检测服务是否正常运行啦。 然后你说阿里云有自动检测的接口,…

一文说明ROS中URDF和SRDF分别是什么

文章目录 前言一、功能作用说明URDFSRDF 二、样例文件说明URDF文件例子SRDF文件例子 总结 前言 URDF全称为Unified Robot Description Format,中文可以翻译为“统一机器人描述格式”。与计算机文件中的.txt文本格式、.jpg图像格式等类似,URDF是一种基于…