FreeRTOS笔记【一】 任务的创建(动态方法和静态方法)

一、任务创建和删除API函数

函数描述
xTaskCreate()使用动态的方法创建一个任务
xTaskCreateStatic()使用静态的方法创建一个任务
xTaskCreateRestricted()创建一个使用MPU进行限制的任务,相关内存使用动态内存分配
vTaskDelete()删除一个任务

二、动态创建任务

2.1 宏定义

使用 xTaskCreate()  函数是在 FreeRTOS 中创建任务的一种方法,使用该函数所需的 RAM 会自动从 FreeRTOS的堆中自动分配。因此需要开启 FreeRTOSConfig.h 中的一个宏定义为1,就可以创建任务了。

#define configSUPPORT_DYNAMIC_ALLOCATION        1     //支持动态内存申请

2.2 函数原型

xTaskCreate() 函数原型如下:

BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,const char * const pcName,const uint16_t usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask )
参数描述
pxTaskCode任务函数
pcName任务名字,一般用于追踪和调试,任务名字长度不能超过configMAX_TASK_NAME_LEN
usStackDepth任务堆栈大小,注意实际申请到的堆栈是usStackDepth的4倍。其中空闲任务的任务堆栈大小为configMINIMAL_STACK_SIZE
pvParameters传递给任务函数的参数
uxPriotiry任务优先级,范围0~ configMAX_PRIORITIES-1
pxCreatedTask任务句柄,任务创建成功以后会返回此任务的任务句柄,这个句柄其实就是任务的任务堆栈。此参数就用来保存这个任务句柄。其他API函数可能会使用到这个句柄。
返回值描述
pdPASS任务创建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY任务创建失败,因为堆内存不足! 

2.3 示例代码

TaskHandle_t Task1_Handler;         //任务句柄
void task_1(void *pvParameters);    //任务函数TaskHandle_t Task2_Handler;         //任务句柄
void task_2(void *pvParameters);    //任务函数int main(void)
{HAL_Init();                     //初始化HAL库   Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhzdelay_init(180);                //初始化延时函数LED_Init();                     //初始化LED KEY_Init();uart_init(115200);              //初始化串口//创建task1任务xTaskCreate((TaskFunction_t )task_1,     	  //任务函数(const char*    )"task_1",   	  //任务名称(uint16_t       )50,              //任务堆栈大小(void*          )NULL,		      //传递给任务函数的参数(UBaseType_t    )2,	              //任务优先级(TaskHandle_t*  )&Task1_Handler); //任务句柄        //创建task2任务xTaskCreate((TaskFunction_t )task_2,     (const char*    )"task_2",   (uint16_t       )50, (void*          )NULL,(UBaseType_t    )2,(TaskHandle_t*  )&Task2_Handler);vTaskStartScheduler();          //开启任务调度
}//task_1任务函数 
void task_1(void *pvParameters)
{while(1)printf("1");
}   //task_2任务函数
void task_2(void *pvParameters)
{while(1)printf("2");
}

 效果:

 

对于 FreeRTOS 来说,同等优先级的任务会在时间片反复切换。在上述代码中,task1 和 task2 的优先级都是2,所以每一个时间片上就会切换一次任务,导致这样的效果。

  2.4 FreeRTOS 内部实现

在图上三个是我们需要编写的,下三步是 FreeRTOS 替我们完成的。

2.5 TCB 任务控制块

本篇暂时不解析其他的流程,我们来详解 TCP 任务控制块。他是一个结构体,可以看成是任务的身份证,每一个任务都有自己任务控制块,结构体成员保存了任务的特征,任务、优先级、任务状态等。

typedef struct tskTaskControlBlock             {// 这里栈顶指针必须位于TCB第一项是为了便于上下文切换操作,详见xPortPendSVHandler中任务切换的操作。volatile StackType_t    *pxTopOfStack;    // 表示任务状态,不同的状态会挂接在不同的状态链表下ListItem_t            xStateListItem;    // 事件链表项,会挂接到不同事件链表下ListItem_t            xEventListItem;        // 任务优先级,数值越大优先级越高UBaseType_t            uxPriority;            // 指向堆栈起始位置,这只是单纯的一个分配空间的地址,可以用来检测堆栈是否溢出StackType_t            *pxStack;            // 任务名char                pcTaskName[ configMAX_TASK_NAME_LEN ];//...省略一些条件编译的成员
} tskTCB;

三、静态创建任务函数

3.1 宏定义

使用函数 xTaskCreateStatic() 来创建任务,也就是静态方法,任务的堆栈、任务控制块就需要由用户来指定了。使用静态方法创建任务的时候需要将宏configSUPPORT_STATIC_ALLOCATION设置为1,在文件FreeRTOSConfig.h中设置。

#define configSUPPORT_STATIC_ALLOCATION 1 //静态内存 

3.2 函数原型

xTaskCreateStatic() 函数原型如下:

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 ) 
参数描述
pxTaskCode任务函数
pcName任务名字,一般用于追踪和调试,任务名字长度不能超过
usStackDepth任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆栈由用户给出,一般是个数组,此参数就是这个数组的大小
pvParameters传递给任务函数的参数
uxPriotiry任务优先级,范围0~ configMAX_PRIORITIES-1
puxStackBuffer任务堆栈,一般为数组,数组类型要为StackType_t类型
pxTaskBuffer任务控制块
返回值描述
NULL任务创建失败,puxStackBuffer或pxTaskBuffer为NULL的时候会导致这个错误的发生
其他值任务创建成功,返回任务的任务句柄。

对比 xTaskCreate() 来说, xTaskCreateStatic() 需要多自定添加 任务堆栈 (puxStackBuffer) 任务控制块 (pxTaskBuffer),也就是说在在静态任务中 TCB 结构体是需要自己定义的。而且在 xTaskCreateStatic() 中,任务句柄并不是作为参数填入,而是返回值。

3.3 定义两个接口函数

开启静态内存的同时需要实现两个函数:(使用静态内存分配任务堆栈和任务控制块内存)

vApplicationGetIdleTaskMemory():空闲任务堆栈函数。实现该函数是为了给内核提供空闲任务关于空闲任务控制块和空闲任务堆栈的相关信息。

vApplicationGetTimerTaskMemory():定时器任务堆栈函数。实现该函数是为了给内核创建定时器任务时提供定时器任务控制块和定时器任务堆栈的相关信息。

//获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的
//静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该
//有用户来提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()
//实现此函数即可。
//ppxIdleTaskTCBBuffer:任务控制块内存
//ppxIdleTaskStackBuffer:任务堆栈内存
//pulIdleTaskStackSize:任务堆栈大小
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
{*ppxIdleTaskTCBBuffer=&IdleTaskTCB;*ppxIdleTaskStackBuffer=IdleTaskStack;*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}//获取定时器服务任务的任务堆栈和任务控制块内存
//ppxTimerTaskTCBBuffer:任务控制块内存
//ppxTimerTaskStackBuffer:任务堆栈内存
//pulTimerTaskStackSize:任务堆栈大小
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize)
{*ppxTimerTaskTCBBuffer=&TimerTaskTCB;*ppxTimerTaskStackBuffer=TimerTaskStack;*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}

3.4 示例代码

//空闲任务任务堆栈
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
//空闲任务控制块
static StaticTask_t IdleTaskTCB;//定时器服务任务堆栈
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
//定时器服务任务控制块
static StaticTask_t TimerTaskTCB;//获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的
//静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该
//有用户来提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()
//实现此函数即可。
//ppxIdleTaskTCBBuffer:任务控制块内存
//ppxIdleTaskStackBuffer:任务堆栈内存
//pulIdleTaskStackSize:任务堆栈大小
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
{*ppxIdleTaskTCBBuffer=&IdleTaskTCB;*ppxIdleTaskStackBuffer=IdleTaskStack;*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}//获取定时器服务任务的任务堆栈和任务控制块内存
//ppxTimerTaskTCBBuffer:任务控制块内存
//ppxTimerTaskStackBuffer:任务堆栈内存
//pulTimerTaskStackSize:任务堆栈大小
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize)
{*ppxTimerTaskTCBBuffer=&TimerTaskTCB;*ppxTimerTaskStackBuffer=TimerTaskStack;*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}TaskHandle_t Task1_Handler;         //任务句柄
void task_1(void *pvParameters);
StackType_t Task1TaskStack[128];    //任务堆栈
StaticTask_t Task1TaskTCB;          //任务控制块  TaskHandle_t Task2_Handler;         //任务句柄
void task_2(void *pvParameters);
StackType_t Task2TaskStack[128];    //任务堆栈
StaticTask_t Task2TaskTCB;          //任务控制块int main(void)
{HAL_Init();                     //初始化HAL库   Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhzdelay_init(180);                //初始化延时函数LED_Init();                     //初始化LED KEY_Init();uart_init(115200);              //初始化串口//创建开始任务taskENTER_CRITICAL();           //进入临界区//创建task1任务Task1_Handler = xTaskCreateStatic((TaskFunction_t )task_1,     	(const char*    )"task_1",   	(uint16_t       )50, (void*          )NULL,				(UBaseType_t    )2,	(StackType_t*   )Task1TaskStack,	(StaticTask_t*  )&Task1TaskTCB);   //创建task2任务Task2_Handler = xTaskCreateStatic((TaskFunction_t )task_2,     (const char*    )"task_2",   (uint16_t       )50, (void*          )NULL,(UBaseType_t    )2,(StackType_t*   )Task2TaskStack,	(StaticTask_t*  )&Task2TaskTCB);        taskEXIT_CRITICAL();            //退出临界区vTaskStartScheduler();          //开启任务调度
}//LED0任务函数 
void task_1(void *pvParameters)
{while(1){printf("1");}
}   //LED1任务函数
void task_2(void *pvParameters)
{while(1){printf("2");}
}

3.5 实现流程

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

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

相关文章

C语言——选择排序

完整代码: //选择排序 // 选择排序是一种简单直观的排序算法。它的工作原理如下:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大&am…

已完结,给小白的《50讲Python自动化办公》

大家好,这里是程序员晚枫,小红薯也叫这个名。 写在前面 上个周末去成都参加了第8届中国开源年会,认识了很多行业前辈和优秀的同龄人。 我发现在工作之外还能有一番事业的人,都有一个让我羡慕的共同点:有一个拿得出手…

Ubantu安装教程(其实和之前CentOS差不多)

文章目录 VM安装见下方参考链接Ubuntu安装我的是Ubuntu22.04.3官网下载我下载的桌面版LTS代表长期支持-这意味着五年的免费安全和维护更新选好版本点击下载就好(注意桌面版和服务器版) 搭建虚拟机个性化名字自定义安装位置不知道就先默认就好&#xff0c…

Java与Redis的集成

目录 Java连接Redis 导入依赖 Redis服务器准备 建立连接 Java操作Redis常用类型数据 Redis字符串(String) Redis哈希(Hash) Redis列表(List) Redis集合(Set) Redis有序集合(Sorted Set) Redis在项目应用…

类和对象解析

导言: Java是一门纯面向对象的语言,在面对对象的世界里,一切皆为对象。而对象的创建又和类的定义息息相关。本文主要阐述了类和对象的使用与理解。解释类的定义方式以及对象的实例化,类中的成员变量和成员方法的使用,…

Python基础入门例程45-NP45 禁止重复注册(条件语句)

最近的博文: Python基础入门例程44-NP44 判断列表是否为空(条件语句)-CSDN博客 Python基础入门例程43-NP43 判断布尔值(条件语句)-CSDN博客 Python基础入门例程42-NP42 公式计算器(运算符)-C…

吴恩达《机器学习》6-1->6-3:分类问题、假设陈述、决策界限

一、什么是分类问题? 在分类问题中,我们试图预测的变量𝑦是离散的值,通常表示某种类别或标签。这些类别可以是二元的,也可以是多元的。分类问题的示例包括: 判断一封电子邮件是否是垃圾邮件(二…

基于鹰栖息算法的无人机航迹规划-附代码

基于鹰栖息算法的无人机航迹规划 文章目录 基于鹰栖息算法的无人机航迹规划1.鹰栖息搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用鹰栖息算法来优化无人机航迹规划。 1.鹰栖息…

汽车标定技术(二)--基于XCP的标定测量实战

目录 1.工程创建 1.1 新建工程 1.2 设备配置 1.3 标定观测 1.4 刷写 2.原始hex文件与标定文件的合并 2.1 修改memory segment file 2.2 标定量地址偏移 ​编辑 2.3 标定后与原始hex文件合并 2.4 标定后直接merge 2.5 不用对ram地址进行偏移实现hex文件合并 本文使用…

linux 安装 elasticsearch 全教程

一、去 elasticsearch官网找到Linux版本的下载链接 地址https://www.elastic.co/cn/downloads/elasticsearch 二、在linux 中用wget下载 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.10.4-linux-x86_64.tar.gz三、下载成功后解压文件 tar -x…

Quartz之JDBC-JobStoreTX配置

一、前言 上篇 《Quartz介绍》中使用的是RAMJobStored存储调度信息,当进程终止调度信息会丢失,本篇我们介绍使用JDBCJobStore来存储调度信息(jobs、Triggers和日历)。 二、Quartz 表结构 可以从官网(http://www.qua…

java入门-JDK下载与安装

1、下载jdk Java 的产品叫JDK(Java Development Kit: Java开发者工具包),必须安装JDK才能使用java 1、官网地址 https://www.oracle.com/java/ https://www.oracle.com/java/technologies/downloads/ 目前比较稳定的版本为 JDK17. 我们就安…

node教程(五)接口+会话

文章目录 一.接口1.1接口是什么?1.2接口的作用1.3接口的开发与调用1.4接口的组成 一.接口 1.1接口是什么? 接口是前后端通信的桥梁 1.2接口的作用 实现前后端通信 1.3接口的开发与调用 大多数接口都是由后端工程师开发的,开发语言不限 一般情况下接口都是由…

Mac 下安装golang环境

一、下载安装包 安装包下载地址 下载完成,直接继续----->下一步到结束即可安装成功; 安装成功之后,验证一下; go version二、配置环境变量 终端输入vim ~/.zshrc进入配置文件,输入i进行编辑 打开的不管是空文本…

【数据开发】大数据平台架构,Hive / THive介绍

1、大数据引擎 大数据引擎是用于处理大规模数据的软件系统, 常用的大数据引擎包括Hadoop、Spark、Hive、Pig、Flink、Storm等。 其中,Hive是一种基于Hadoop的数据仓库工具,可以将结构化的数据映射到Hadoop的分布式文件系统上,并提…

Linux上编译sqlite3库出现undefined reference to `sqlite3_column_table_name‘

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> 在Ubuntu 18上编译sqlite3库后在运行程序时出现undefined reference to sqlite3_column_table_name’的错误。网上的说法是说缺少SQLITE_ENABLE_COLUMN_M…

基于若依的ruoyi-nbcio流程管理系统增加仿钉钉流程设计(六)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 这节主要讲条件节点与并发节点的有效性检查,主要是增加这两个节点的子节点检查,因为…

idea2023 PoJie以后无法修改内存无效

1. 打开电脑环境变量 2. 找到对应pojie文件 vmoptions目录 3. 修改这个文件 添加或者修改配置 -Xms128m -Xmx8192m4. 重启idea 修改成功

使用 ChatGPT 提升 LeetCode 刷题效率

文章目录 1 背景2 操作步骤 1 背景 在做 LeetCode 的 SQL 题库时, 想在本地调试, 需要在本地的数据库上创建表以及准备测试数据, 大家都是有经验的开发人员, 简单粗暴的办法就不讲了 可以借助 ChatGPT 的能力, 生产数据库的表以及测试数据的 sql, 提升刷题效率 2 操作步骤 将…

阿里云多款ECS产品全面升级 性能最多提升40%

“阿里云始终围绕‘稳定、安全、性能、成本、弹性’的目标不断创新,为客户创造业务价值。”10月31日,杭州云栖大会上,阿里云弹性计算计算产品线负责人张献涛表示,通过持续的产品和技术创新,阿里云发布了HPC优化实例等多…