前言

资源:

任务概念

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

线程:线程是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 -「51nod 1868」彩色树

    \(\mathcal{Description}\)   Link & 双倍经验 Link.   给定一棵 \(n\) 个结点的树,每个结点有一种颜色.记 \(g(u,v)\) 表示 \(u\) ...

  2. 自创Web框架之过度Django框架

    目录 自创Web框架之过度Django框架 软件开发架构 HTTP协议 Web框架之"撸起袖子加油干" Web框架之通过wsgiref加油干 封装优化处理 动静网页 jinjia2 ...

  3. 关于Untiy破解 for Mac

    Mac的破解很简单 也很坑 如果你破解过win的 在进行Mac版的破解 可能认为三观都被颠覆了 以下进行下讲解 并且帮助大家排除坑 还是那句话  有条件的请支持正版  破解版只进行技术分享 第一步去u ...

  4. Element-UI整合VUE下拉选项无法选中的一个小问题

    searchObj: { subjectId: ''// 解决查询表单无法选中二级类别,必须要现在模型中给一个空的初始值 },

  5. pytest(3)-测试命名规则

    前言 在自动化测试项目中,单元测试框架运行时需要先搜索测试模块(即测试用例所在的.py文件),然后在测试模块中搜索测试类或测试函数,接着在测试类中搜索测试方法,最后加入到队列中,再按执行顺序执行测试. ...

  6. tor-browse

    https://sourceforge.net/projects/t-browser/

  7. 漏洞CVE 2017-8464

    概述 微软的Patch Tuesday更新发布了多达95个针对Windows.Office.Skype.IE和Edge浏览器的补丁.其中27个涉及远程代码执行,18个补丁被微软设定为严重(Critic ...

  8. Meterpreter核心命令

    实验目的 掌握Meterpreter常见的基本命令的使用 实验原理 1.Meterpreter介绍 meterpreter是metasploit框架中的一个扩展模块,作为溢出成功以后的攻击载荷使用,攻 ...

  9. FPGA+x86构建高性能国产网络测试仪竞技之道

    众所周知,以太网已经深入我们的生活无处不在,企业.校园.大数据中心和家庭等都离不开网络,否则我们的生活将受到严重的影响. 以太网的接口速率也是迅速发展:10M.100M.GE.10GE.40GE.10 ...

  10. .net mvc项目本地调试:浏览器一直转圈无法访问

    原因: 通过 bundles.Add 方式給多个 js文件添加 匿名,再通过  @Scripts.Render 引入的时候, js 里面使用了 const 来定义变量,就会导致访问pending,具体 ...