当前位置: 首页 > news >正文

从零开始掌握FreeRTOS(4)任务的动态和静态创建

 

目录

任务控制块

环境准备

任务创建宏

硬件初始化

 添加外设文件

动态创建任务

定义动态任务函数

 定义任务句柄

任务创建函数

main函数实现

效果展示

静态创建任务

修改宏

定义静态任务函数

空闲任务与定时器任务堆栈函数和任务控制块指针

 定义任务控制块指针和栈以及任务句柄 

任务创建函数

 main函数实现

效果展示

多任务创建


      前面我们已经梳理了 FreeRTOS 中链表的相关内容,从本篇开始,我们将学习任务。

        我们在前面提到过,任务就是一个个不断执行功能的死循环函数。在裸机系统中,单片机实现的所有功能都放在while循环下。在 FreeRTOS 中也是一样,只不过将不同的功能放在不同的死循环函数中,由调度器来管理这些任务的运行。

        在程序运行时,全局变量与局部变量的定义,中断发生时当前状态的存储,函数返回地址等都需要内存来存放。这些内容都存放在栈里面。在裸机系统中,上述所有的东西都存在同一段栈空间内。

        对于操作系统来讲,栈的分配与释放均由其自动实现。如果把裸机系统的循环看作一个任务的话,由于操作系统存在多个任务且任务间相互独立,所以每个任务都有一段独立的栈空间。

任务控制块

        在 task.c 中,有一个任务控制块(TCB)的声明。TCB就相当于任务的身份证,包括任务的所有信息,比如任务的栈指针, 任务名等。通过任务控制块,操作系统可以通过任务控制块来实现对任务的全部操作。

        下面为TCB结构体声明。

typedef struct tskTaskControlBlock
{volatile StackType_t	*pxTopOfStack;	#if ( portUSING_MPU_WRAPPERS == 1 )xMPU_SETTINGS	xMPUSettings;		#endifListItem_t			xStateListItem;	ListItem_t			xEventListItem;		UBaseType_t			uxPriority;			StackType_t			*pxStack;			char				pcTaskName[ configMAX_TASK_NAME_LEN ];#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )StackType_t		*pxEndOfStack;		#endif#if ( portCRITICAL_NESTING_IN_TCB == 1 )UBaseType_t		uxCriticalNesting;	#endif#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t		uxTCBNumber;		UBaseType_t		uxTaskNumber;		#endif#if ( configUSE_MUTEXES == 1 )UBaseType_t		uxBasePriority;		UBaseType_t		uxMutexesHeld;#endif#if ( configUSE_APPLICATION_TASK_TAG == 1 )TaskHookFunction_t pxTaskTag;#endif#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )void			*pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];#endif#if( configGENERATE_RUN_TIME_STATS == 1 )uint32_t		ulRunTimeCounter;	#endif#if ( configUSE_NEWLIB_REENTRANT == 1 )struct	_reent xNewLib_reent;#endif#if( configUSE_TASK_NOTIFICATIONS == 1 )volatile uint32_t ulNotifiedValue;volatile uint8_t ucNotifyState;#endif#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )uint8_t	ucStaticallyAllocated; 		#endif#if( INCLUDE_xTaskAbortDelay == 1 )uint8_t ucDelayAborted;#endif} tskTCB;

以下对一些重要内容进行解释。

pxTopOfStack:栈顶指针

xStateListItem:链表节点。在链表部分,节点内有个TCB指针指向该节点;在TCB中,就是通过这个指针来指向这个节点。

xEventListItem:这个是指向事件链表的指针,功能和上个一样。

uxPriority:优先级。

pxStack:任务栈起始地址。

pcTaskName:任务名称,内容格式为字符串,长度由宏 configMAX_TASK_NAME_LEN 来控制,这个宏在 FreeRTOSConfig.h 中定义,默认为 16。

        接下来,我们就开始进行简单实战来验证。

环境准备

        无论是创建动态还是静态任务,我们都需要做一些提前准备,比如配置创建任务方式的宏,还有硬件初始化等。

任务创建宏

        首先,我们需要在 FreeRTOSConfig.h 中定义支持动态和静态声明的宏。这两个宏在        FreeRTOS.h 中有相关定义,在其中如果我们没有定义下面这两个宏,系统则会默认定义他们。

#define configSUPPORT_STATIC_ALLOCATION     0
#define configSUPPORT_DYNAMIC_ALLOCATION    1

        在上述两行代码中,我们开启动态创建而关闭了静态创建。需要注意的是,我们不能同时开启动态和静态创建,如果同时开启的话则会在编译的时候爆出问题。 

http://www.xdnf.cn/news/491185.html

相关文章:

  • 实验-实现向量点积-RISC-V(计算机组成原理)
  • 使用 ESP32 驱动 ±12V 压电无源蜂鸣器(NPN 三极管 + PWM 控制驱动电路)
  • Typescript学习教程,从入门到精通,TypeScript 流程控制语法知识点及案例代码(4)
  • Docker镜像和容器有什么区别
  • NDK19无法在AppleM芯片运行解决方案
  • 深入C++的set集合:用法、特性与应用实例
  • 2025 家用投影新标杆:雷克赛恩 CyberPro1 如何重新定义客厅观影体验
  • 新京东,正在成为一种生活方式
  • Transformer网络结构
  • 【笔记】 huggingface.co:443是连接出错吗
  • Node.js 实战二:接口参数校验与类型安全方案
  • 主打「反激进」的一汽丰田,靠稳扎稳打的技术实现突围
  • 实战记录:Java 高并发插入 MySQL 唯一索引表引发死锁的排查与解决
  • Windows 本地部署MinerU详细教程
  • 厂房气楼做法
  • [Lc] 5.16 One question a day周总结
  • 项目管理进阶:全文解读企业IT系统全生命周期管理与运营平台建设方案【附全文阅读】
  • 【RTMP】RTMP协议的详细介绍
  • SpringBoot3.4.5下Lombok的@Data注解不生效,解决方案
  • Gmsh 读取自定义轮廓并划分网格:深入解析与实践指南
  • 金格iWebOffice控件在新版谷歌Chrome中不能加载了怎么办?
  • 数字电路的发展历史
  • PT2031单触控单输出触摸IC
  • MySQL8.x新特性:窗口函数(Window Functions)
  • 【Linux】ssh命令 – 安全的远程连接服务
  • GPU Runtime Suspend 调试与验证:从 sysfs 到 perf 分析
  • ROS2学习(5)------ROS2 功能包介绍
  • 【python】直线型雷达图
  • 前端流行框架Vue3教程:18. _组件数据传递
  • 关于“集合框架底层原理”的一些问题