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);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2LED_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);			//´ò¿ªLEDvTaskDelay(500);//delay_ms(500);GPIO_SetBits(GPIOA,GPIO_Pin_8);			//´ò¿ªLEDvTaskDelay(500);}
}void led1(void)
{while(1){GPIO_ResetBits(GPIOD,GPIO_Pin_2);			//´ò¿ªLEDvTaskDelay(500);//delay_ms(500);GPIO_SetBits(GPIOD,GPIO_Pin_2);			//´ò¿ªLEDvTaskDelay(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延时函数。

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

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

相关文章

Flask实战

from flask import Flask appFlask(__name__)点击Flask同时点击键盘ctrl即可查看Flask的默认初始化函数 def __init__(self,import_name: str,static_url_path: str | None None,static_folder: str | os.PathLike[str] | None "static",static_host: str | None …

安装docker的PHP环境NLMP环境在国产deepin操作系统上

1: 先安装docker 安装完后执行,权限设置 sudo usermod -aG docker $USER或者sudo usermod -aG docker kentrl#添加当前用户到Docker用户组中 sudo newgrp docker#更新用户组数据,必须执行否则无效 sudo systemctl restart docker 先看目录结构: 2:按照目录结构挂载磁盘,…

JavaScript(五)-正则表达式

文章目录 正则表达式正则表达式的介绍语法元字符修饰符 正则表达式 正则表达式的介绍 什么是正则表达式 正则表达式&#xff08;Regular expression&#xff09;是用于匹配字符串中字符组合的模式&#xff0c;在JavaScript中&#xff0c;正则表达式也是对象通常用来查找、替…

UE5数字孪生系列笔记(四)

场景的切换 创建一个按钮的用户界面UMG 创建一个Actor&#xff0c;然后将此按钮UMG添加到组件Actor中 调节几个全屏的背景 运行结果 目标点切换功能制作 设置角色到这个按钮的位置效果 按钮被点击就进行跳转 多个地点的切换与旋转 将之前的目标点切换逻辑替换成旋转的逻…

气象观测站点数据下载与处理

一、下载途径 全国400多个气象站气候数据&#xff08;1942-2022&#xff09; 王晓磊&#xff1a;中国空气质量/气象历史数据 | 北京市空气质量历史数据 气象数据免费下载网站整理 中国气象站观测的气象数据怎么下载 二、R语言处理 2.1 提取站点文件 library(dplyr) library(…

集成智能楼宇的微网系统多时间尺度MPC调度方法(附带Matlab代码)

含多智能楼宇的微网示意图如图所示&#xff0c;包括多个智能楼宇、微网可控分布式电源 、储能系统以及通信链路。其中&#xff0c;每个智能楼宇系统包括制冷设备、常规用电设备以及屋顶光伏系统。各单元功能介绍如下 针对含多智能楼宇的微网系统&#xff0c;提出一种基于模型预…

gpt能生成ppt吗

gpt能生成ppt吗 GPT是一个高度通用的工具&#xff0c;适用于多种场景和领域&#xff0c;制作ppt只是它强大功能的冰山一角&#xff0c;具体包括&#xff1a; 信息查询与解释&#xff1a; 提供科学、技术、历史、文化等领域的详细解释和背景信息。 解答疑问&#xff0c;帮助…

制作带有中文字体的 jdk 17 镜像

1. 准备中文字体 将所有需要添加的中文字体放进一个文件夹内&#xff0c;例如 fonts 2. 创建 Dockerfile 文件 Dockefile 文件与 fonts 文件夹放在同一目录下 # 使用 slim 版本的 jdk 17 镜像作为基础镜像 FROM openjdk:17-slim# 安装字体工具 RUN apt-get update &&a…

Xilinx 7系列FPGA 高性能(HP)接口与2.5V/3.3V 外设IO接口设计考虑

引言&#xff1a;Xilinx 7系列FPGA IO Bank分为HP Bank和HR Bank&#xff0c;HP IO接口电压范围为1.2V~1.8V&#xff0c;可以实现高性能&#xff0c;HR IO接口电压范围为1.2V~3.3V。当HR Bank与2.5V或者3.3V外设互联时&#xff0c;需要考虑接口电平的兼容性。根据性能需求、功能…

模拟相机拍照——对文档进行数据增强

一. 背景 假如我们有一个标准文件&#xff0c;我们对其进行文字识别、版面分析或者其他下游任务就比较容易。然而&#xff0c;当图片是手机拍照获取的&#xff0c;图片中往往有阴影、摩尔纹、弯曲。 那么&#xff0c;如何通过标准的文档&#xff0c;获得类似相机拍照的图片呢&…

家庭营销广告Criteo公司首次获得MRC零售媒体测量认证

家庭营销广告Criteo公司首次获得零售媒体测量MRC认证 商业媒体公司Criteo2024年3月28日宣布&#xff0c;它首次获得媒体评级委员会&#xff08;MRC&#xff09;的认证&#xff0c;在其企业零售媒体平台commerce Max和commerce Yield上&#xff0c;在桌面、移动网络和移动应用内…

4-Java方法详解

目录 Java方法详解 1、什么是方法 2、方法的定义及调用 3、方法重载 4、命令行传参 5、可变参数 6、递归 例题&#xff1a;代码实现一个计算机 Java方法详解 1、什么是方法 2、方法的定义及调用 形参&#xff1a;用来定义作用的 实参&#xff1a;实际调用传递给他的参数…

C#基于SSE传递消息给Vue前端实现即时单向通讯

一、简述 通常前端调用后端的API&#xff0c;调用到了&#xff0c;等待执行完&#xff0c;拿到返回的数据&#xff0c;进行渲染&#xff0c;流程就完事了。如果想要即时怎么办&#xff1f;如果你想问什么场景非要即时通讯&#xff0c;那可就很多了&#xff0c;比如在线聊天、实…

Java 笔记 01:Java 概述,MarkDown 常用语法整理

一、前言 记录时间 [2024-04-18] 昨天整理完 Docker 基础后略微思索了一下&#xff0c;还是决定把 Java 捡起来&#xff0c;系统地学习一遍&#xff0c;参考的学习课程是狂神说 Java 零基础&#xff0c;真诚感激此系列视频对笔者的帮助。 零基础可以学 Java 吗&#xff1f;只要…

JVS低代码平台表单引擎:字符串拼接与逻辑函数的完美结合

字符串拼接使用逻辑函数配置 示例场景&#xff1a;通过按钮触发逻辑使用函数将两个日期字段组合为范围时间类型。 选择开始日期和结束日期后&#xff0c;点击【合并】按钮自动处理回显至起止日期字段。在【合并】按钮上设置逻辑。 注意&#xff1a;这里【起止日期】组件是数组…

【web开发02】后端开发Maven

后端开发Maven 1 Maven是什么&#xff1f;1.1 Maven基础概念1.1.2 仓库1.1.3 坐标 2 配置maven环境3 创建maven项目4 导入maven项目4 依赖管理4.1 依赖配置4.2 依赖传递4.2.1 排除依赖 4.3 依赖范围4.4 生命周期4.4.1 运行生命周期 1 Maven是什么&#xff1f; Maven本质是项目…

二次元AI绘画生成器免费:教你生成精美图片

二次元AI绘画生成器&#xff0c;无疑是现代技术与艺术完美结合的典范。这些工具不仅将复杂的绘画过程简化&#xff0c;更让每一个艺术爱好者的创意得以充分展现。这些生成器能够精准捕捉大家的创意精髓&#xff0c;将其转化为细腻、独特的二次元画作。无论是角色设计、场景描绘…

SpringMVC(五)【拦截器】

前言 今天来把 SpringMVC 最后一部分学完&#xff0c;虽然课时很短&#xff0c;但是学起来还是很慢的&#xff0c;不过确收获很大。不得不感慨学大数据确实有必要把 SSM、SpringBoot 等各种 JavaEE 技术好好学一学&#xff0c;收获很大&#xff0c;尽管我们到现在 Java 代码写了…

Redis几种常见的应用方式

1.登录认证 redis最常见的应用就是&#xff0c;登录认证把。再首次登录返回给前端token&#xff0c;把用户名和登录状态缓存到redis一段时间&#xff0c;每次其他请求进来过滤器那这token解析出来的用户名或其他关键的key值&#xff0c;再redis里面查询缓存&#xff0c;有则直…

【算法】二分查找

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、二分查找二、查找元素的第一个和最后一个位置三、x的平方根四、搜索插入位置五、山脉数组的峰顶索引…