前言

资源:

任务概念

进程:进程是程序执行的过程,是程序在执行过程中分配和管理资源的基本单位。拥有独立的虚拟地址空间。

线程:线程是CPU调度和分派的基本单位。与其它同一进程的线程共享当前进程资源。

协程:比线程更加轻量级的存在,不是由操作系统内核管理,而是由程序控制的。其实就是在同一线程内时分地执行不同的子程序。(注意:不是函数调用)

还有管程、纤程。

并发:多个任务看起来是同时进行, 这是一种假并行。

并行:并行是指令同一时刻一起运行。

对于目前主流的RTOS的任务,大部分都属于并发的线程。

因为MCU上的资源每个任务都是共享的,可以认为是单进程多线程模型。

任务状态

freertos有四种状态,每种状态都有对应的状态链表管理。

运行态:占用CPU使用权时的状态。

就绪态:能够运行(没有被阻塞和挂起),但是当前没有运行的任务的状态。

阻塞态:由于等待信号量、消息队列、事件标志组、调用延迟函数等而处于的状态被称之为阻塞态。

挂起态:调用函数vTaskSuspend()对指定任务进行挂起,挂起后这个任务将不被执行。

  • 调用函数xTaskResume()可退出挂起状态。
  • 不可以指定超时周期事件(不可以通过设定超时事件而退出挂起状态)

任务状态转换图:

任务优先级

每个任务被分配一个从0到(configMAX_PRIORITIES - 1)的优先级。

configMAX_PRIORITIES 是在 FreeRTOSConfig.h文件中被定义。

优先级数值越高,优先级越高。

idle任务的优先级为0。

多个任务可以共享一个任务优先级。

如果在FreeRTOSConfig.h文件中配置宏定义configUSE_TIME_SLICING为1,或者没有配置此宏定义,时间片调度都是使能的。

使能时间片后,处于就绪态的多个相同优先级任务将会以时间片切换的方式共享处理器。

如果硬件架构支持CLZ指令,可以使用该特性,使能配置如下:

  1. FreeRTOSConfig.hconfigUSE_PORT_OPTIMISED_TASK_SELECTION设置为1;
  2. 最大优先级数目configMAX_PRIORITIES不能大于CPU位数。

空闲任务和空闲任务钩子

空闲任务

空闲任务是启动RTOS调度器时由内核自动创建的任务,其优先级为0,确保系统中至少有一个任务在运行。

空闲任务可用来释放RTOS分配给被删除任务的内存。

空闲任务钩子

空闲任务钩子是一个函数,每一个空闲任务周期被调用一次。

空闲任务钩子应该满足一下条件:

  1. 不可以调用可能引起空闲任务阻塞的API函数;
  2. 不应该陷入死循环,需要留出部分时间用于系统处理系统资源回收。

创建空闲钩子

FreeRTOSConfig.h头文件中设置configUSE_IDLE_HOOK为1;

定义一个函数,名字和参数原型如下所示:

void vApplicationIdleHook( void ); // FreeRTOS 规定了函数的名字和参数

一般设置CPU进入低功耗模式都是使用空闲任务钩子函数实现的。

创建任务

任务的创建有两种:创建静态内存任务和创建动态内存任务。

任务参数相关概念

任务入口函数:即是任务函数,是该任务需要跑的函数。

任务名称:即是任务名,主要用于调试。

任务堆栈大小:即是任务栈大小,单位是word。

任务入口函数参数:传递给任务入口函数的参数。在任务函数里,通过形参获得。

任务控制块:主要用于内核管理任务,记录任务信息。

任务句柄:用于区分不同的任务,用于找到该任务的任务控制块。

创建静态内存任务

xTaskCreateRestrictedStatic(),该函数不讲解,因为需要MPU,想研究的同学可以参考:freertos官网API

配置静态内存

创建静态内存任务需要先实现以下内容:

  1. 需要在FreeRTOSConfig.h打开configSUPPORT_STATIC_ALLOCATION宏,开启静态内存。

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

    1. vApplicationGetIdleTaskMemory():空闲任务堆栈函数。
    2. vApplicationGetTimerTaskMemory():定时器任务堆栈函数。
  3. 注意静态内存对齐。

实现空闲任务堆栈函数

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

/* 空闲任务控制块 */
static StaticTask_t Idle_Task_TCB;
/* 空闲任务任务堆栈 */
static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE]; /** @brief vApplicationGetIdleTaskMemory
* @details 获取空闲任务的任务堆栈和任务控制块内存
* @param
* @retval
* @author lizhuming
*/
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize)
{
*ppxIdleTaskTCBBuffer = &Idle_Task_TCB; /* 任务控制块内存 */
*ppxIdleTaskStackBuffer = Idle_Task_Stack; /* 任务堆栈内存 */
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* 任务堆栈大小 */
}

实现定时器任务堆栈函数

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

/* 定时器任务控制块 */
static StaticTask_t Timer_Task_TCB;
/* 定时器任务堆栈 */
static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH]; /** @brief vApplicationGetTimerTaskMemory
* @details 获取定时器任务的任务堆栈和任务控制块内存
* @param
* @retval
* @author lizhuming
*/
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize)
{
*ppxTimerTaskTCBBuffer = &Timer_Task_TCB;/* 任务控制块内存 */
*ppxTimerTaskStackBuffer = Timer_Task_Stack;/* 任务堆栈内存 */
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;/* 任务堆栈大小 */

配置内存对齐

内存对齐的配置在portmacro.h里面的portBYTE_ALIGNMENT宏,按自己需求配置即可。

在任务堆栈初始化时会把栈顶指针纠正为内存对齐。参考下列代码:

pxTopOfStack = &( pxNewTCB->pxStack[ ulStackDepth - ( uint32_t ) 1 ] );
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );

纠正后可以通过以下代码检查是否正确的代码如下:

configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

分配静态内存

静态内存分配是有编译器决定的。

在freertos中,创建任务需要分配的内存主要是任务控制块和任务堆栈。

/* 任务控制快 */
static StaticTask_t lzmStaticTestTaskTCB = {0};
/* 任务堆栈 */
static StackType_t lzmStaticTestTaskStack[256] = {0};

创建任务原型

创建任务函数原型:

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 ) // 任务控制块

创建任务

/* 创建静态内存任务 */
lzmStaticTestTaskHandle = xTaskCreateStatic((TaskFunction_t) lzmStaticTestTask, // 任务入口函数
(const char*) "lzm static test task", // 任务函数名
(uint32_t )256, // 任务堆栈大小
(void* )NULL, // 传递给任务入口函数的参数
(UBaseType_t)5, // 任务优先及
(StackType_t* )lzmStaticTestTaskStack, // 任务堆栈地址
(StaticTask_t* )&lzmStaticTestTaskTCB); // 任务控制块地址

创建动态内存任务

配置动态内存

动态内存配置是在FreeRTOSConfig.h配置的,这些内存主要供给FreeRTOS动态内存分配函数使用。

#define configTOTAL_HEAP_SIZE	( ( size_t ) ( 32 * 1024 ) ) // 系统总堆大小

而freertos的动态内存管理是有文件heap_x.c实现的,具体实现算法,后面讲到内存时会分析。

uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; // 系统总堆

任务句柄

static TaskHandle_t lzmTestTaskHandle = NULL;

创建任务原型

创建任务函数原型:

BaseType_t xTaskCreate( // 返回任务句柄
TaskFunction_t pxTaskCode, // 任务入口函数
const char * const pcName, // 任务名称
const configSTACK_DEPTH_TYPE usStackDepth, // 任务堆栈大小
void * const pvParameters, // 传递给任务入口函数的参数
UBaseType_t uxPriority, // 任务优先级
TaskHandle_t * const pxCreatedTask ) // 任务控制块指针

创建任务

/* 创建动态内存任务 */
xReturn = xTaskCreate((TaskFunction_t) lzmTestTask, // 任务入口函数
(const char*) "lzm test task", // 任务函数名
(uint16_t )256, // 任务堆栈大小
(void* )NULL, // 传递给任务入口函数的参数
(UBaseType_t)5, // 任务优先及
(TaskHandle_t* )&lzmTestTaskHandle); // 任务句柄

删除任务

配置删除任务

在文件FreeRTOSConfig.h中,必须定义宏INCLUDE_vTaskDelete 为 1,删除任务的API才会失效。

调用API删除任务后,将会从就绪、阻塞、暂停和事件列表中移除该任务。

如果是动态内存创建任务,删除任务后,其占用的空间资源有空闲任务释放,所以删除任务后尽量保证空闲任务获取一定的CPU时间。

如果是静态内存创建任务,删除任务后,需要自己处理释放任务占用的空间资源。

删除任务原型

void vTaskDelete( TaskHandle_t xTaskToDelete ); // 参数为任务句柄

注意:传入的参数为任务句柄,当出入的参数为NULL时,表示删除调用者当前的任务。

实战

源码:拉取 freertos_on_linux_task_01 文件夹

结果:

【freertos】003-任务基础知识的更多相关文章

  1. FreeRTOS学习笔记——FreeRTOS 任务基础知识

    RTOS 系统的核心就是任务管理,FreeRTOS 也不例外,而且大多数学习RTOS 系统的工程师或者学生主要就是为了使用RTOS 的多任务处理功能,初步上手RTOS 系统首先必须掌握的也是任务的创建 ...

  2. FreeRTOS基础知识

    前面一篇文章介绍了一些命名规范之类的基础知识,但是我觉得还缺少一定前言知识,就是裸机和操作系统有什么区别,为什么我们需要学freertos,因为招聘要求?那么为什么招聘网又会有这个要求呢?所以我们为什 ...

  3. JAVA学习基础知识总结(原创)

    (未经博主允许,禁止转载!) 一.基础知识:1.JVM.JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. java语言是跨平 ...

  4. Spring笔记01(基础知识)

    1.基础知识 01.Spring:轻量级Java EE开源框架,它是由Rod Johnson为了解决企业应用程序开发的复杂性而创建. 02.目标:实现一个全方位的整合框架,实现“一站式”的企业应用开发 ...

  5. Vue学习之--------消息订阅和发布、基础知识和实战应用(2022/8/24)

    文章目录 1.基础知识 2.代码实例 2.1 main.js 2.2 School.vue 2.3 Student.vue 2.4 App.vue 3.全局事件总线通信改为消息的订阅和发布 3.1 核 ...

  6. .NET面试题系列[1] - .NET框架基础知识(1)

    很明显,CLS是CTS的一个子集,而且是最小的子集. - 张子阳 .NET框架基础知识(1) 参考资料: http://www.tracefact.net/CLR-and-Framework/DotN ...

  7. RabbitMQ基础知识

    RabbitMQ基础知识 一.背景 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然 ...

  8. Java基础知识(壹)

    写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...

  9. selenium自动化基础知识

    什么是自动化测试? 自动化测试分为:功能自动化和性能自动化 功能自动化即使用计算机通过编码的方式来替代手工测试,完成一些重复性比较高的测试,解放测试人员的测试压力.同时,如果系统有不份模块更改后,只要 ...

  10. [SQL] SQL 基础知识梳理(一)- 数据库与 SQL

    SQL 基础知识梳理(一)- 数据库与 SQL [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902856.html 目录 What's 数据库 ...

随机推荐

  1. Solution -「UOJ #450」复读机

    \(\mathcal{Description}\)   Link.   求从 \(m\) 种颜色,每种颜色无限多的小球里选 \(n\) 个构成排列,使得每种颜色出现次数为 \(d\) 的倍数的排列方案 ...

  2. Python基础—迭代器、生成器(Day13)

    一.迭代器 1.可迭代对象:遵循可迭代协议,内部含有__iter__方法的对象就叫做可迭代对象.(str.list.tulpe.dict.set) 查询数据类型的方法 s = 'laonanhai' ...

  3. 轻量级DI框架Guice使用详解

    背景 在日常写一些小工具或者小项目的时候,有依赖管理和依赖注入的需求,但是Spring(Boot)体系作为DI框架过于重量级,于是需要调研一款微型的DI框架.Guice是Google出品的一款轻量级的 ...

  4. Https原理与演变

    巨人的肩膀 为了一个HTTPS,浏览器操碎了心··· (qq.com)

  5. MySQL是怎么保证redo log和binlog是完整的?

    摘要:WAL机制保证只要redo log和binlog保证持久化到磁盘,就能确保MySQL异常重启后,数据可以恢复. 本文分享自华为云社区<MySQL会丢数据吗?>,作者: JavaEdg ...

  6. 【axios三部曲】一、使用axios

    axios作为一个基于promise的网络请求库,它同时支持浏览器和node环境,是我们开发中常用的一个库 ​ 它的一些特性: 从浏览器发出XMLHttpRequests 从node.js发出http ...

  7. [源码解析] NVIDIA HugeCTR,GPU 版本参数服务器---(7) ---Distributed Hash之前向传播

    [源码解析] NVIDIA HugeCTR,GPU 版本参数服务器---(7) ---Distributed Hash之前向传播 目录 [源码解析] NVIDIA HugeCTR,GPU 版本参数服务 ...

  8. 入门pwn的练习

    都是比较简单的一些pwn的题目,也是团队里面的一个人发着做的,因为是初学,所以就还是先从简单的向难得方向去发展. 第一个 先用checksec或者die检测一下, 然后拖入到IDA,shift+f12 ...

  9. 数据可视化地图制作教程,这个免费BI软件轻松搞定

    ​数据可视化地图制作教程 现在做数据分析基本上离不开数据可视化,在大量的数据中,有很大一部分数据都与地理信息相关,因此,在数据可视化中,可视化地图是非常重要的一部分.无论是新闻报道,还是商业分析报告, ...

  10. 在服务器的docker里 装anacond3深度学习环境的全流程超基础

    ​ 背景: 实验室给我分配了一个服务器 已经装好了docker 和nvidi docker . 现在我的目标是创建我自己的docker 然后在我自己的docker里装上anaconda环境. 我以前从 ...