FreeRTOS之动态创建任务与删除任务

1.本文是利用FreeRTOS来动态创建任务和删除任务。主要是使用FreeRTOS的两个API函数:xTaskCreate()和vTaskDelete()。

任务1和任务2是让LED0、LED1闪烁。任务3是当按键按下时删除任务1。

使用动态创建任务时,需要动态的堆中申请任务所需的内存空间,所以首先需要将FreeRTOS.h中的宏定义(configSUPPORT_DYNAMIC_ALLOCATION)设置为1。

使用vTaskDelete()时需要将如下宏定义设置为1:

2.xTaskCreate()函数的6个参数参数说明:

任务优先级对应的数值越大,其优先级越高。任务句柄是相当于任务的身份证(ID),以方便其他函数通过任务句柄对其进行操作,比如vTaskDelete()中传入的任务句柄,即为删除任务句柄所对应的任务。

3.vTaskDelete()函数的参数说明:

当传入的参数为NULL,表述删除当前正在运行的任务。

4.代码:

(1)main.c:

#include "stm32f10x.h"
#include "led.h"
//#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "sys.h"

//¶¨Òåstart_taskµÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 64
TaskHandle_t start_handler;
void start_task(void);

//¶¨ÒåÈÎÎñ1µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED0_TASK_PRIO 2
#define LED0_TASK_STACK_SIZE 64
TaskHandle_t led0_handler;
void led0(void);

//¶¨ÒåÈÎÎñ2µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED1_TASK_PRIO 3
#define LED1_TASK_STACK_SIZE 64
TaskHandle_t led1_handler;
void led1(void);

//¶¨ÒåÈÎÎñ2µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define KEY_TASK_PRIO 4
#define KEY_TASK_STACK_SIZE 64
TaskHandle_t key_handler;
void key_task(void);

int flag = 0;

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2
	LED_Init();
	KEY_Init();
	
	xTaskCreate((TaskFunction_t) start_task,																//ÈÎÎñº¯Êý
							(const char *)"start_task",																	//ÈÎÎñÃû³Æ
							(uint16_t)START_TASK_STACK_SIZE,											      //ÈÎÎñ¶ÑÕ»´óС
							(void *)NULL,																								//´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
							(UBaseType_t)START_TASK_PRIO,																//ÈÎÎñÓÅÏȼ¶
							(TaskHandle_t *)&start_handler);														//ÈÎÎñ¾ä±ú
	
			
	vTaskStartScheduler();																								//¿ªÊ¼ÈÎÎñµ÷¶È
}

/*´´½¨¿ªÊ¼ÈÎÎñ£º*/
void start_task(void)
{
//	taskENTER_CRITICAL();	
	/*´´½¨ÈÎÎñ*/
	if(flag == 0)
	{
		xTaskCreate((TaskFunction_t) led0,																		//ÈÎÎñº¯Êý
							(const char *)"led0_task",																//ÈÎÎñÃû³Æ
							(uint16_t)LED0_TASK_STACK_SIZE,											      //ÈÎÎñ¶ÑÕ»´óС
							(void *)NULL,																							//´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
							(UBaseType_t)LED0_TASK_PRIO,															//ÈÎÎñÓÅÏȼ¶
								(TaskHandle_t *)&led0_handler);														//ÈÎÎñ¾ä±ú
		xTaskCreate((TaskFunction_t) led1,
								(const char *)"led1_task",
								(uint16_t)LED1_TASK_STACK_SIZE,
								(void *)NULL,
								(UBaseType_t)LED1_TASK_PRIO,
								(TaskHandle_t *)&led1_handler);
		xTaskCreate((TaskFunction_t) key_task,
								(const char *)"key_task",
								(uint16_t)KEY_TASK_STACK_SIZE,
								(void *)NULL,
								(UBaseType_t)KEY_TASK_PRIO,
								(TaskHandle_t *)&key_handler);
	 flag = 1;
	}
	 vTaskDelay(500);
										
	 vTaskDelete(NULL);											//ɾ³ýµ±Ç°ÈÎÎñ
//	 taskEXIT_CRITICAL();
}

void led0(void)
{
	while(1)
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_8);			//´ò¿ªLED
		vTaskDelay(500);
		//delay_ms(500);
		GPIO_SetBits(GPIOA,GPIO_Pin_8);			//´ò¿ªLED
		vTaskDelay(500);
	}
}

void led1(void)
{
	while(1)
	{
		GPIO_ResetBits(GPIOD,GPIO_Pin_2);			//´ò¿ªLED
		vTaskDelay(500);
		//delay_ms(500);
		GPIO_SetBits(GPIOD,GPIO_Pin_2);			//´ò¿ªLED
		vTaskDelay(500);
	}
}

/*´´½¨°´¼üÈÎÎñ£º*/
void key_task(void)
{
	uint8_t key = 0;
    while(1)
    {
        //printf("task3ÕýÔÚÔËÐУ¡£¡£¡\r\n");
        //key = KEY_Scan(0);
        if(KEY_0 == 0)
        {
            if(led0_handler != NULL)
            {
                //printf("ɾ³ýtask1ÈÎÎñ\r\n");
                vTaskDelete(led0_handler);
                led0_handler = NULL;
            }

        }
        vTaskDelay(10);
    }
}

(2)led.c和led.h:

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

void KEY_Init(void)
{
	/*1.¶¨ÒåÒý½ÅµÄ½á¹¹Ìå¡£
	  2.ʹÄÜÒý½Å¶ÔÓ¦µÄʱÖÓ¡£
	  3.ÅäÖÃÒý½ÅÐÅÏ¢*/
	
	//¶¨ÒåÒý½Å½á¹¹Ì壺
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//ʹÄÜʱÖÓ£º
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);
	
	//ÅäÖÃÒý½ÅÐÅÏ¢(KEY0)£º
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	
	//ÅäÖÃKEY1£º
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //ÉèÖóÉÉÏÀ­ÊäÈë

	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//ÅäÖð´¼üWK_UP:
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
}

void KEY_Scan(void)
{
	static u8 key_up = 1;				//°´¼üËÉ¿ª±ê־λ
	if(key_up && (KEY_0 == 0||  KEY_1  == 0|| KEY_1 == 1))
	{
		//delay_ms(10);						  //È¥¶¶¶¯
		key_up = 0;
		if(KEY_0 == 0)
		{
			GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
			GPIO_SetBits(GPIOA,GPIO_Pin_8);
			//delay_ms(1000);
		}
		else if(KEY_1 == 0)
		{
			GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
			GPIO_SetBits(GPIOD,GPIO_Pin_2);
			//delay_ms(1000);
		}
		else if(KEY_2 == 1)
		{
			GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
			GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
		}
	}
	else if(KEY_0==1&&KEY_1==1&&KEY_2==0)
	{
		key_up = 1;
	}
}

#ifndef __LED_H
#define	__LED_H

#include "stm32f10x.h"

void LED_Init(void);

#endif

(3)key.c和key.h代码:

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

void KEY_Init(void)
{
	/*1.¶¨ÒåÒý½ÅµÄ½á¹¹Ìå¡£
	  2.ʹÄÜÒý½Å¶ÔÓ¦µÄʱÖÓ¡£
	  3.ÅäÖÃÒý½ÅÐÅÏ¢*/
	
	//¶¨ÒåÒý½Å½á¹¹Ì壺
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//ʹÄÜʱÖÓ£º
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);
	
	//ÅäÖÃÒý½ÅÐÅÏ¢(KEY0)£º
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	
	//ÅäÖÃKEY1£º
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //ÉèÖóÉÉÏÀ­ÊäÈë

	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//ÅäÖð´¼üWK_UP:
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
}

void KEY_Scan(void)
{
	static u8 key_up = 1;				//°´¼üËÉ¿ª±ê־λ
	if(key_up && (KEY_0 == 0||  KEY_1  == 0|| KEY_1 == 1))
	{
		//delay_ms(10);						  //È¥¶¶¶¯
		key_up = 0;
		if(KEY_0 == 0)
		{
			GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
			GPIO_SetBits(GPIOA,GPIO_Pin_8);
			//delay_ms(1000);
		}
		else if(KEY_1 == 0)
		{
			GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
			GPIO_SetBits(GPIOD,GPIO_Pin_2);
			//delay_ms(1000);
		}
		else if(KEY_2 == 1)
		{
			GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
			GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
		}
	}
	else if(KEY_0==1&&KEY_1==1&&KEY_2==0)
	{
		key_up = 1;
	}
}

#ifndef __KEY_H
#define __KEY_H

#include "stm32f10x.h"

#define KEY_0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)			//¶ÁÈ¡°´¼üµÄ״̬
#define KEY_1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)
#define KEY_2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)

void KEY_Init(void);
void KEY_Scan(void);						//°´¼üɨÃ躯Êý

#endif

(3)delay代码:

#include "delay.h"

static uint16_t fac_ms = 8;

extern void xPortSysTickHandler(void);

//systickÖжϷþÎñº¯Êý,ʹÓÃucosʱÓõ½
void SysTick_Handler(void)
{	
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//ϵͳÒѾ­ÔËÐÐ
    {
        xPortSysTickHandler();	
    }
}

void delay_us(uint32_t us)
{
	uint32_t i;
	
	//1.Ñ¡ÔñHCLKʱÖÓ£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµ
	SysTick_Config(72);
	
	for(i = 0;i < us;i++)
	{
		while(!((SysTick->CTRL) & (1 << 16)));		//µÈ´ý¼ÆÊýÍê³É
	}
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	//Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}

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));				//ÆÕͨ·½Ê½ÑÓʱ
}

void delay_xms(uint32_t ms)								//·â×°ÈÎÎñÇл»µÄÑÓʱº¯Êý
{
	if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)				//Èç¹ûϵͳÒѾ­ÔÚÔËÐУ¬Ôò¿ªÊ¼ÑÓʱ
	{
		if(ms >= fac_ms)
		{
			vTaskDelay(ms / fac_ms);
		}
		ms %= fac_ms;													//µ±OSÎÞ·¨ÌṩÕâôСµÄÑÓʱʱ£¬Ê¹ÓÃÆÕͨÑÓʱ
	}
	delay_ms((uint32_t)(ms*1000));				//ÆÕͨÑÓʱ
}






#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"

void delay_us(uint32_t us);									//ÑÓʱ΢Ãë
void delay_ms(uint32_t ms);									//ÑÓʱºÁÃë

void delay_xms(uint32_t ms);								//·â×°ÈÎÎñÇл»µÄÑÓʱº¯Êý

#endif

5.运行结果:

6.总结:

动态创建任务是系统自动分配内存,设置好相关的宏定义后,直接对应函数API即可。删除任务时也是利用API函数去完成。

在做本文实验,一开始每当按下按键时,程序就跑飞了。后面才发现,用来是按键部分的延时有问题。当时移植FreeRTOS后,delay部分的延时函数需要进行修改。本文为了方便实验,取消了按键的防止抖动延时。此处需要注意,当需要使用非FreeRTOS的延时函数时,一定要配置好新的delay延时函数。

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

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

相关文章

OpenHarmony多媒体-ohos_videocompressor

介绍 videoCompressor是一款ohos高性能视频压缩器。 目前实现的能力&#xff1a; 支持视频压缩 使用本工程 有两种方式可以下载本工程&#xff1a; 开发者如果想要使用本工程,可以使用git命令 git clone https://gitee.com/openharmony-sig/ohos_videocompressor.git --…

Redis学习记录

Redis安装 首先是Redis的下载地址&#xff0c;事实上&#xff0c;Redis已经出到7的版本了&#xff0c;我们这里使用的是5的版本。&#xff08;3也能用&#xff09; Redis下载地址 我们将Redis下载下来并解压&#xff1a; 我们如何启动呢? redis-server.exe redis.windows.…

单分支:if语句

示例&#xff1a; /*** brief how about if? show you here.* author wenxuanpei* email 15873152445163.com(query for any question here)*/ #define _CRT_SECURE_NO_WARNINGS//support c-library in Microsoft-Visual-Studio #include <stdio.h>#define if_state…

学习笔记------约束的管理

此篇记录FPGA的静态时序分析&#xff0c;在学习FPGA的过程中&#xff0c;越发觉得对于时序约束只是懂了个皮毛。现在记录一下自己的学习过程。 本文摘自《VIVADO从此开始》高亚军 为什么要进行约束&#xff1f;约束的目的是什么&#xff1f; 简单来说&#xff0c;就是需要在…

Unity(MVC思想)

MVC 一下演示使用MVC和不使用MVC的做法区别。 前两个没有使用MVC 主面板逻辑&#xff1a; mainPanel是该脚本名字 每个场景中不一定存在该面板&#xff0c;单纯的显隐需要去手动挂载过于麻烦。 所以自己读取创建面板出来(每个场景仅创建一次)&#xff0c;存下该面板&#xf…

OpenHarmony网络请求库-httpclient

简介 HTTP是现代应用程序通过网络交换数据和媒体的的主要方式。httpclient是OpenHarmony 里一个高效执行的HTTP客户端&#xff0c;使用它可使您的内容加载更快&#xff0c;并节省您的流量。httpclient以人们耳熟能详的OKHTTP为基础&#xff0c;整合android-async-http&#xf…

FPGA核心板在声呐系统中的应用

前言 声纳系统使用声脉冲来探测、识别和跟踪水下物体。一个完整的声纳系统是由一个控制和显示部件、一个发射器电路、一个接收器电路和同时能作为发射装置&#xff08;扬声器&#xff09;和探测装置&#xff08;高灵敏度麦克风&#xff09;的传感器组成。 声纳系统图 技术挑战…

list基础知识

list 1.list 的定义和结构 list 是双向链表&#xff0c;是C的容器模板&#xff0c;其接收两个参数&#xff0c;即 list(a,b) 其中 a 表示指定容器中存储的数据类型&#xff0c;b 表示用于分配器内存的分配器类型&#xff0c;默认为 list <int>; list 的特点&#xff1a;…

鸿蒙开发岗突增!它和前端开发到底有哪些区别和联系?

2024年1 月 18 日&#xff0c;鸿蒙 Next 预览版面向开发者正式开放申请。至此&#xff0c;鸿蒙原生应用版图已成型&#xff0c;这个中国自主研发的操作系统&#xff0c;正式走上了独立之路。 有许多的公司都陆续地加入了鸿蒙原生应用开发的队列&#xff0c;从年初宣布的200个应…

MySQL高负载排查方法最佳实践(15/16)

高负载排查方法 CPU占用率过高问题排查 使用mpstat查看cpu使用情况。 # mpstat 是一款 CPU 性能指标实时展示工具 # 能展示每个 CPU 核的资源视情况&#xff0c;同时还能将资源使用情况进行汇总展示 # 如果CPU0 的 %idle 已经为 0 &#xff0c;说明此核已经非常繁忙# 打印所…

京西商城——前端项目的创建以及前后端联调

创建VUE项目 在jingxi_shop_project文件夹中再创建一个 frontend 文件夹用来存放前端项目 /jingxi_shop_project/backend/jingxi_shop_project....../frontend/jingxi_shop_web......首先要安装 node.js 和 VUE cli&#xff0c;进入到项目目录内创建项目 vue create jingxi_…

【JavaEE多线程】Thread类及其常见方法(上)

系列文章目录 &#x1f308;座右铭&#x1f308;&#xff1a;人的一生这么长、你凭什么用短短的几年去衡量自己的一生&#xff01; &#x1f495;个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C,自顶向下看Java-CSDN博客 ❤️相关文章❤️&#xff1a;清灵白羽 漾情天…

类和对象(中)(构造函数、析构函数和拷贝构造函数)

1.类的六个默认成员函数 任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 //空类 class Date{}; 默认成员函数&#xff1a;用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数 2.构造函数 构造函数 是一个 特殊的成员函数&a…

接口自动化入门: Http请求的域名与IP地址概念!

在进行接口自动化测试时&#xff0c;经常需要与服务器进行通信&#xff0c;这就涉及到了使用Http协议发送请求。在发送请求时&#xff0c;我们需要指定目标服务器的域名或者IP地址。下面将从0到1详细介绍域名与IP地址的概念及其在接口自动化测试中的应用。 本文从5个方面来书写…

3D可视化技术:研发基地的科技新篇章

在科技日新月异的今天&#xff0c;我们生活在一个充满无限可能性的时代。而在这个时代中&#xff0c;3D可视化技术正以其独特的魅力&#xff0c;引领着科技领域的新一轮变革。 3D可视化技术通过三维图像的方式&#xff0c;将现实世界或虚拟世界中的物体、场景等以立体、逼真的形…

改进下记录学习的小网站

Strong改进 结束&#xff1a;2024-4-14 打算投入&#xff1a;10h 实际消耗&#xff1a;12h 3m 学习总是不在状态。 我的时间花得很零散&#xff0c;也有点茫然。所以想尝试一下集中式地、一块一块地花&#xff0c;比如投入30个小时&#xff0c;去干一件事&#xff0c;这样就可…

npm怎么迁移到pnpm

下载的vue3模板用到了pnpm&#xff0c;就安装了一下 但是安装之后使用pnpm install 就发现包全被移动到ignored文件夹下面了,还报错 PS G:\Projects\gitProeject\TS_front> pnpm installWARN  Moving commitlint/config-conventional that was installed by a different …

继电器会不会被淘汰?

继电器作为一种电控制器件&#xff0c;其基本功能是在输入量达到一定条件时&#xff0c;使电气输出电路中的被控量发生预定的阶跃变化。 尽管现代电子技术发展迅速&#xff0c;新型产品不断涌现&#xff0c;但继电器因其独特的优势在许多应用领域仍然不可替代。 技术优势&#…

git 删除本地分支 删除远程仓库中的分支

语法&#xff1a; 删除本地分支 git branch -D <分支名>删除远程分支 git push <remote名称> <分支名> --delete 示例&#xff1a; 删除本地分支 git branch -D feature/test_listview删除远程分支 git push origin feature/test_listview --delete 两个…

FebHost:谁可以注册.CA加拿大域名?

在加拿大&#xff0c;互联网域名的注册管理遵循一套独特的规则。特别是对于代表加拿大身份的顶级域名“.ca”&#xff0c;其申请和注册过程涉及一些严格的条件。这些条件确保了只有符合特定标准的个人或实体才能获得这一具有国家象征意义的网络地址。 首先&#xff0c;想要注册…