FreeRTOS的任务操作

文章目录

  • 3 FreeRTOS任务操作
    • 3.1 创建task
    • 3.2 删除task
      • 3.2.1 空闲(idle)任务(守护任务)
      • 3.2.2 钩子(Hook)函数
    • 3.3 设置,获取,task优先级
      • 3.3.1 设置任务优先级
      • 3.3.2 获取任务优先级
    • 3.4 任务示例

3 FreeRTOS任务操作

3.1 创建task

​ 任务的创建不代表任务的执行,任务创建后还需要使用调度器来让任务执行。即vTaskStartScheduler();同时创建任务函数,不等于任务处理函数。他只是创建了任务,但是没有规定任务要做什么。

有动态创建和静态创建两种创建方式:

  • 动态分配:只需要我们提供任务的堆栈大小和返回句柄,TCB任务块,任务堆栈的大小是动态分配的,系统会使用malloc等函数分配的,内存在堆区,基本方式是使用xTaskCreate()函数动态分配,这也是我们常用的分配方式,使用动态分配时,会自己自动实现malloc和free功能。
  • 静态分配:提供任务的堆栈大小和返回句柄的同时,还需要提供堆栈空间和任务控制块,,基本使用方式是使用xTaskCreateStatic()函数动态分配。
/*			@brief	动态分配内存创建任务函数@retval pdTRUE:创建成功,errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:内存不足创建失败 @param  pvTaskCode:是一个函数指针,用来指向任务处理函数pcName:任务的名字usStackDepth:给这个任务分配的栈的深度,注意单位是word,1表示4个字节,而不是1个字节。pvParameters:调用任务处理函数时传入的参数uxPriority:这个任务的优先级别pxCreatedTask:任务句柄,之后对这个任务的操作都通过他来操作,类似于文件描述符。句柄类型是TaskHandle_t类型。
*/
BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,const char * const pcName,const uint16_t usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask );/*@brief  静态分配内存创建任务函数@retval 创建成功的任务句柄@param pvTaskCode:任务函数pcName:任务名称usStackDepth:任务栈深度,单位为字(word)pvParameters:任务参数uxPriority:任务优先级puxStackBuffer:任务栈空间数组,创建任务的堆栈首地址pxTaskBuffer:任务控制块存储空间
*/
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 );//创建一个任务处理函数,即任务创建后,被调度器执行的时候做什么事情。函数原型如下:
//TaskFunction_t是一个函数指针,指向void FunctionName (void*)这样的函数
typedef void (* TaskFunction_t)( void * );
//所以我们对应的函数应该长这个样子:
void TaskFunctionName( void *pvParameters );

ps:任务控制块地址和任务句柄并不相同,我们操控任务是通过任务句柄操作的,任务句柄最终指向任务控制块。

根据任务处理函数的原型,我们可以知道,规定任务处理函数时,需要有以下特点:

  1. 这个函数不能有返回值
  2. 他的参数void *pvParameters 是通过创建任务函数xTaskCreate的参数传递进来的。
  3. 可以用同一个任务处理函数创建多个任务,也就是说,多个任务执行同一个事情。

ps:因为每次创建任务的时候,都会分配栈空间, 这就意味着任务1的局部变量存储在任务1的栈空间中,而任务2的局部变量存储在任务2的栈空间中,但是有全局变量时,我们应该像多线程使用临界资源那样,对全局变量进行保护和防止冲突,因为全局变量的内存时多个任务公用的。这也就是为什么我们说,任务这个概念更类似与线程,而不是进程的原因。

3.2 删除task

​ 删除一个任务/释放一个任务的资源。使用vTaskDelete();可以删除使用xTaskCreate()函数创建的任务,也可以删除xTaskCreateStatic()函数创建的任务。

/*			@brief:删除一个任务函数@retval:None@param:TaskHandle_t xTaskToDelete:任务对应的句柄,当这个句柄的值为NULL时,代表释放自己的资源。
*/
void vTaskDelete(TaskHandle_t xTaskToDelete)

3.2.1 空闲(idle)任务(守护任务)

​ FreeRTOS的调度器决定了任何时刻处理器必须有一个任务运行,当所有的任务都处于阻塞或挂起等状态不能运行时,空闲任务就会被执行,同时,我们在创建任务后,当然需要删除(释放)该任务函数所使用的内存,这个清理的工作,就是由空闲任务来完成的。空闲任务有如下特点:

  • 对于自杀的任务,内存由空闲任务进行清理。
  • 对于被杀的任务,由调用了vTaskDelete这个函数的任务内部清理(凶手任务调用这个函数,由凶手任务清理)。
  • 空闲任务的任务优先级为0,它不能阻碍用户的任务运行。
  • 空闲任务要么处于就绪Ready态,要么处于运行态,永远不会阻塞!

ps:**也正是因为空闲任务的优先级为0(最低),所以使用vTaskDelete释放自己或其他任务时,一定要保证有机会让空闲任务执行,否则资源是得不到释放的。**举个例子,task1和task2的优先级分别为1和2,task2优先级较高所以优先执行,若task2自杀后,轮到task1执行,若task1一直处于运行态,不释放CPU的执行权限,那么task2的TCB任务块和相应的堆栈资源就一直不会被清理。空闲任务是在调度器vTaskStartScheduler()调度时自动创建的第一个任务。

3.2.2 钩子(Hook)函数

​ 相当于向空闲任务的处理函数中添加了处理程序。使能后,当调度器调度内核进入空闲任务时就会调用钩子函数

//一般情况下这个宏为0,在FreeRTOSConfig.h文件中
#define configUSE_IDLE_HOOK			0
若要使能钩子函数,需要将宏定义为1,同时编辑extern void vApplicationIdleHook( void ); 函数,这里实现我们在空闲任务中想要额外实现的功能。(钩子函数并不会取消原先空闲任务中的释放内存的功能)。

在钩子函数中万万不可以使用while()或者会造成一直阻塞的函数。

3.3 设置,获取,task优先级

3.3.1 设置任务优先级

/*			@brief:用来设置任务的优先级@retval:None@param:TaskHandle_t xTask:对应要设置的任务的句柄UBaseType_t uxNewPriority:新的优先级,取值范围是0~(configMAX_PRIORITIES-1 )
*/
void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority);

3.3.2 获取任务优先级

/*			@brief:用来获取任务优先级@retval:返回优先级@param:const TaskHandle_t xTask:获取这个句柄的优先级,若为NULL,那么获取自己的优先级,返回值UBaseType_t是返回的优先级
*/
UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask)

3.4 任务示例

#include "main.h"
#include "usart.h"
#include "gpio.h"#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "task.h"
#include "list.h"
#include "queue.h"
#include "freeled.h"void led_task(void *param);
void usart_task(void *param);//。。。GPIO_INIT()等INIT初始化。。。int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();//创建两个任务xTaskCreate(led_task, "task1", 100, NULL, 1, NULL);xTaskCreate(usart_task, "task2", 100, NULL, 1, NULL);vTaskStartScheduler();
}//两个任务处理函数
void led_task(void *param)
{while(1){blink_led(BLUE_LED, 500, 1);blink_led(RED_LED, 500, 1);blink_led(GREEN_LED, 500, 1);}vTaskDelete( NULL );
}void usart_task(void *param)
{while(1){printf("This is task 2\n");vTaskDelay( pdMS_TO_TICKS(1000));}vTaskDelete( NULL );
}
//实现led和printf
#define ON 1
#define OFF 0typedef struct gpio_s{GPIO_TypeDef		*group;uint16_t				pin;
}gpio_t;enum ENUM_LED{RED_LED,GREEN_LED,BLUE_LED,LED_MAX,
};void turn_led(uint32_t which_led, uint32_t led_state);
int blink_led(int which_led, int interval, int num);
gpio_t leds[LED_MAX] = {{REDLED_GPIO_Port, REDLED_Pin},{GREENLED_GPIO_Port, GREENLED_Pin},{BLUELED_GPIO_Port, BLUELED_Pin},
};void turn_led(uint32_t which_led, uint32_t led_state)
{GPIO_PinState				level;if (which_led >= LED_MAX){return ;}level = (led_state == OFF) ? GPIO_PIN_SET : GPIO_PIN_RESET;HAL_GPIO_WritePin(leds[which_led].group, leds[which_led].pin, level);return ;
}int blink_led(int which_led, int interval, int num)
{if (num<0 || interval<=0 || which_led>LED_MAX){return -1;}while( num-- ){turn_led(which_led, ON);vTaskDelay(pdMS_TO_TICKS(interval));turn_led(which_led, OFF);vTaskDelay(pdMS_TO_TICKS(interval));//注意这里替换成freertos的延时};return 0;
}

需要注意的是,在使用了FreeRTOS后,我们应该摒弃使用HAL库中的Delay()函数,中断函数等,避免造成系统的崩溃。

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

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

相关文章

自动驾驶---Motion Planning之多段五次多项式

1 前言 在之前的博客系列文章中和读者朋友们聊过Apollo的 Motion Planning方案: 《自动驾驶---Motion Planning之LaneChange》 《自动驾驶---Motion Planning之Path Boundary》 《自动驾驶---Motion Planning之Speed Boundary》 《自动驾驶---Motion Planning之轨迹Path优化》…

Oracle 上机

--1.&#xff08;3分&#xff09;查找每个部门的最高工资员工编号及其下属信息。 select e2.empno,e1.* from emp e1 join ( select * from emp where (deptno,sal) in (select deptno,max(sal) from emp group by deptno)) e2 on e1.mgr e2.empno; /* 2.&#xff08;5分&…

Spring Boot集成checkstyle快速入门Demo

1.什么是checkstyle&#xff1f; CheckStyle是一个帮助程序员来遵守一直的编码规范的工具。默认&#xff0c;它支持google 和sun 的java style guide。而且它是高度可配置的&#xff0c;允许自定义编码规范&#xff0c;并可以对各种IDE&#xff08;eclipse、Intellij&#xff…

昇思MindSpore学习笔记2-01 LLM原理和实践 --基于 MindSpore 实现 BERT 对话情绪识别

摘要&#xff1a; 通过识别BERT对话情绪状态的实例&#xff0c;展现在昇思MindSpore AI框架中大语言模型的原理和实际使用方法、步骤。 一、环境配置 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下…

前端在for循环中使用Element-plus el-select中的@click.native动态传参

<el-table ref"table" :data"editTableVariables" cell-dblclick"handleRowDblClick" style"width: 100%" > <!-- el-table-column: 表格列组件&#xff0c;定义每列的展示内容和属性 --><el-table-column prop&q…

8种数据迁移工具

前言 最近有些小伙伴问我&#xff0c;ETL数据迁移工具该用哪些。 ETL(是Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程)&#xff0c;对于企业应用来说&#xff0c;我们经常会遇到各种数据的处理、转换、迁移的场景。 今天特地给大家汇总了一些目前…

【云原生】服务网格(Istio)如何简化微服务通信

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、微服务架构的兴起 2、Istio&#xff1a;服务网格的佼…

服务器测评

服务器测评 Linux测评口令是否存在空口令账户密码长度和密码定期更换密码复杂度本地登录失败处理功能相关参数超时锁定sshd服务相关端口是否已经打开不允许root账户远程登录查看SELinux状态审计查看Linux中正在运行的服务查看已添加的iptables规则查看文件和目录的权限设置是否…

大文件上传是怎么做的

1. 分片上传 1. 把需要上传的文件按照一定的规则&#xff0c;分割成相同大小的数据块 2. 初始化一个分片上传任务&#xff0c;返回本次分片上传的唯一标识 3. 按照一定的规则把各个数据块上传 4. 发送完成后&#xff0c;服务端会判断数据上传的完整性&#xff0c;如果完整&a…

【Python】Python环境搭建教学#保姆级教学#手把手带你安装——内附Python环境搭建安装包(Python、PyCharm(社区版)安装包)

Python环境搭建 导读一、初识Python1.1 Python的由来1.2 Python的用途1.3 Python的优缺点1.4 Python的前景&#xff08;钱景&#xff09; 二、Python环境搭建2.1 运行环境——Python安装2.2 开发环境——PyCharm安装2.3 项目创建2.4 基本配置2.4.1 主题配置2.4.2 背景图设置2.4…

Vue笔记-vue中使用JS创建的函数

主要是公司对前端要求不高&#xff0c;能解决问题就行了&#xff0c;前端不太熟&#xff0c;用js这种处理起来方便&#xff0c;在此记录下。 在src中创建一个api目录&#xff0c;新建custom.js export const getDivHeightByClass (className) > {let divElements docume…

容器之docker

Docker 是一个开源的平台&#xff0c;旨在使应用程序的开发、部署和运行更加轻松。它利用容器技术&#xff0c;将应用程序及其依赖环境打包在一起&#xff0c;以便于在任何环境中一致运行。 概述 Docker 通过提供轻量级的虚拟化解决方案&#xff0c;使得开发者可以轻松创建、…

.NET 调用API创建系统服务实现权限维持

01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏&#xff0c;主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧&#xff0c;对内网和后渗透感兴趣的朋友们可以订阅该电子报刊&#xff0c;解锁更多的报刊内容。 02基本介绍 本文内容部分节选自小报童…

达梦数据库的DBMS_STATS包

达梦数据库的DBMS_STATS包 基础信息 OS版本&#xff1a; Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本&#xff1a; DM Database Server 64 V8 DB Version: 0x7000c 03134284132-20240115-215128-20081达梦数据库&#xff08;DM Database&#xff09;提供了 D…

FreeRTOS开发五、任务状态切换以及空闲任务回收结束的任务

1、任务状态切换 任务创建的时候就会处于就绪状态ready&#xff0c;然后他马上就能够运行进入Running状态&#xff0c;运行中可以调用vTaskDelay进入阻塞状态&#xff0c;实际就是延时一小段时间&#xff0c;等待唤醒&#xff0c;当延时时间过去后就回到了就绪状态&#xff0…

【python学习】自定义函数的一些高级用法-1

在 Python 中&#xff0c;自定义函数除了基本的定义和调用外&#xff0c;还有一些高级用法&#xff0c;可以让函数更加灵活和强大。以下是一些自定义函数的高级用法示例&#xff1a; 1. 默认参数 函数定义时可以指定默认参数值&#xff0c;当调用函数时没有提供该参数的值时&…

深入理解Spring Boot与Spring Cloud的整合方式

深入理解Spring Boot与Spring Cloud的整合方式 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨Spring Boot与Spring Cloud的整合方式&#x…

pytorch-ResNet18简单复现

目录 1. ResNet block2. ResNet18网络结构3. 完整代码3.1 网络代码3.2 训练代码 1. ResNet block ResNet block有两个convolution和一个short cut层&#xff0c;如下图&#xff1a; 代码&#xff1a; class ResBlk(nn.Module):def __init__(self, ch_in, ch_out, stride):su…

Java学习 (六) 面向对象--this、继承、方法重写、super

一、this 关键字 1、this 演示 vi Person.java public class Person {String name;int age;//显示声明构造器public Person(String s , int i){name s;age i;}public void setAge(int age){age age;}}vi PersonTest.java public class PersonTest {public static void m…