【FreeRTOS】【STM32】06 FreeRTOS的使用-动态创建多任务 FreeRTOS 的启动流程

主要流程参照【FreeRTOS】【STM32】06 FreeRTOS的使用-动态创建单任务

1.定义任务句柄

static TaskHandle_t AppTaskCreate_Handle = NULL;

2.硬件初始化

3.创建具体功能任务函数

见定义任务函数

4.使用xTaskCreate创建任务

 xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */(const char* )"AppTaskCreate",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL,/* 任务入口函数参数 */(UBaseType_t )1, /* 任务的优先级 */(TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */

5.使用vTaskStartScheduler(); /* 启动任务,开启调度 */

主要代码清单

头文件
  /** ************************************************************************* 包含的头文件* ************************************************************************* //* FreeRTOS 头文件 */#include "FreeRTOS.h"#include "task.h"/* 硬件 bsp 头文件 */#include "bsp_usart.h"...
声明和定义
/**************************** 任务句柄 ********************************//** 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么* 这个句柄可以为 NULL。*//* 创建任务句柄 */static TaskHandle_t AppTaskCreate_Handle = NULL;/* LED1 任务句柄 */ static TaskHandle_t LED1_Task_Handle = NULL; /* LED2 任务句柄 */ static TaskHandle_t LED2_Task_Handle = NULL; /***************************** 内核对象句柄 ******************************//** 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核* 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我* 们就可以通过这个句柄操作这些内核对象。** 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,* 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数* 来完成的**//************************** 全局变量声明 *********************************//** 当我们在写应用程序的时候,可能需要用到一些全局变量。*//*************************************************************************** 函数声明**************************************************************************/static void AppTaskCreate(void);/* 用于创建任务 */static void LED1_Task(void* pvParameters);/* LED1_Task 任务实现 */ static void LED2_Task(void* pvParameters);/* LED2_Task 任务实现 */ static void BSP_Init(void);/* 用于初始化板载相关资源 */
main函数
 /****************************************************************** @brief 主函数* @param 无* @retval 无* @note 第一步:开发板硬件初始化第二步:创建 APP 应用任务第三步:启动 FreeRTOS,开始多任务调度****************************************************************/int main(void){BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,表示是否创建成功,默认为 pdPASS *//* 硬件初始化 */BSP_Init();/* 创建 AppTaskCreate 任务 */
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */(const char* )"AppTaskCreate",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL,/* 任务入口函数参数 */(UBaseType_t )1, /* 任务的优先级 */(TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针,任务句柄 *//* 启动任务调度 */
if (pdPASS == xReturn)vTaskStartScheduler(); /* 启动任务,开启调度 */
elsereturn -1;while (1); /* 正常不会执行到这里 */}
任务入口函数
 /************************************************************************ @ 函数名 : AppTaskCreate* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面* @ 参数 : 无* @ 返回值 : 无*******************************************************************/static void AppTaskCreate(void){BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */taskENTER_CRITICAL(); //进入临界区/* 创建 LED_Task 任务 */ xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */ (const char* )"LED1_Task",/* 任务名字 */ (uint16_t )512, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )2, /* 任务的优先级 */ (TaskHandle_t* )&LED1_Task_Handle);/* 任务控制块指针 */ if (pdPASS == xReturn) printf("创建 LED1_Task 任务成功!\r\n"); /* 创建 LED_Task 任务 */ xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */ (const char* )"LED2_Task",/* 任务名字 */ (uint16_t )512, /* 任务栈大小 */ (void* )NULL, /* 任务入口函数参数 */ (UBaseType_t )3, /* 任务的优先级 */ (TaskHandle_t* )&LED2_Task_Handle);/* 任务控制块指针 */ if (pdPASS == xReturn) printf("创建 LED2_Task 任务成功!\r\n"); vTaskDelete(AppTaskCreate_Handle); //删除 AppTaskCreate 任务taskEXIT_CRITICAL(); //退出临界区}

XX,启动!

一个RTOS工程的启动遵循这两个流程。
第一种

/* 硬件初始化 */
硬件初始化。硬件初始化这一步还属于裸机的范畴
/* RTOS 系统初始化 */
RTOS 系统初始化
/* 创建任务 1,但任务 1 不会执行,因为调度器还没有开启 */ 
创建各种任务。这里把所有要用到的任务都创建好,但还不会进入调度,因为这个时候 RTOS 的调度器还没有开启。
/* 创建任务 2,但任务 2 不会执行,因为调度器还没有开启 */
启动 RTOS 调度器,开始任务调度。这个时候调度器就从刚刚创建好的任务中选择一个优先级最高的任务开始运行。
/* 启动 RTOS,开始调度 */

第二种

/* 硬件初始化 *//* RTOS 系统初始化 *//* 创建一个任务 */
创建一个开始任务。然后在这个初始任务里面创建各种应用任务
/* 启动 RTOS,开始调度 */
启动 RTOS 调度器,开始任务调度。这个时候调度器就去执行刚刚创建好的初始任务,也就是创建任务的任务创建任务。每创建一个任务后它都将进入就绪态,系统会进行一次调度,如果新创建的任务的优先级比初始任务的优先级高的话,那将去执行新创建的任务,当新的任务阻塞时再回到初始任务被打断的地方继续执行。反之,则继续往下创建新的任务,直到所有任务创建完成。各种应用任务创建完成后,初始任务自己关闭自己,使命完成。

FreeRTOS 的启动流程

1.上电 Reset_Handler

我们知道单片机上电之后,从Flash启动时在取得栈顶指针之后,执行 Reset_Handler,复位函数的最后会调用 C 库函数__main。__main 函数的主要工作是初始化系统的堆和栈,最后调用 C 中的 main 函数,从而去到 C 的世界。

 Reset_Handler PROCEXPORT Reset_Handler[WEAK]IMPORT __mainIMPORT SystemInitLDR R0, =SystemInitBLX R0LDR R0, =__mainBX R0ENDP

2.xTaskCreate创建任务

到达main函数之后, xTaskCreate()函数创建任务,并且创建任务函数内部 FreeRTOS 会自动帮我们做初始化的事情,比如初始化堆内存

3.开启任务调度

创建完成任务之后,空闲任务定时器任务均未实现,这些都是在开启调度函数vTaskStartScheduler()中实现的。

为什么要空闲任务?因为 FreeRTOS 一旦启动,就必须要保证系统中每时每刻都有一个任务处于运行态(Runing),并且空闲任务不可以被挂起与删除,空闲任务的优先级是最低的,以便系统中其他任务能随时抢占空闲任务的 CPU 使用权。这些都是系统必要的东西,由FreeRTOS自动实现。

动态创建空闲任务

空闲任务的优先级与堆栈大小都在 FreeRTOSConfig.h 中由用户定义,空闲任务的任务句柄存放在静态变量 xIdleTaskHandle 中,用户可以调用 API 函数 xTaskGetIdleTaskHandle()获得空闲任务句柄。 FreeRTOS自动完成。

创建定时器任务

如果在 FreeRTOSConfig.h 中使能了 configUSE_TIMERS 这个宏定义 ,FreeRTOS自动完成。

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

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

相关文章

PyTorch 模型性能分析和优化 - 第 6 部分

玩具模型 为了方便我们的讨论,我们使用流行的 timm python 模块(版本 0.9.7)定义了一个简单的基于 Vision Transformer (ViT) 的分类模型。我们将模型的 patch_drop_rate 标志设置为 0.5,这会导致模型在每个训练步骤中随机丢弃一半…

基于Qt QSpinBox 微调框小案例

修改微调框数值的方式包括: 单击右侧的向上/向下按钮 按键盘的向上/向下键 在微调框获取焦点时,通过鼠标滚轮的上下滚动 当然了,也允许用户手动输入 其中: QSpinBox - 用于整数的显示和输入 QDoubleSpinBox - 用于浮点数的显示和输入 它们都是 QAbstractSpinBox 的子类,具…

线程安全之锁的原理

🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️林 子       🛰️博客专栏:✈️ Linux       🛰️社区 :✈️ 进步学堂       &#x1f6f0…

10.7写作练习

慎用定冠词the少用since,多用as:Since there are many TV programs that feature colorful experiences, --> As many TV programs have colourful experiences,动名词作主语,后面加三单注意表意准确无歧义 No, I disagree with the idea …

QCC51XX-QCC30XX系列开发教程(实战篇) 之 12.5-空间音频用开发板调试配置说明

查看全部教程开发请点击:全网最全-QCC51xx-QCC30xx(TWS)系列从入门到精通开发教程汇总(持续更新中) ==================================================================== 版权归作者所有,未经允许,请勿转载。 ==========================================

可观测性-Metrics-WebClient异步Http远程Call

代码示例 1.依赖导入 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><ar…

根据ip及子网掩码得出网段

function calculateIPRange(ip, subnetMask) {// 将IP地址和子网掩码转换为二进制形式const ipBinary ip.split(.).map(part > parseInt(part, 10).toString(2).padStart(8, 0)).join();const subnetBinary subnetMask.split(.).map(part > parseInt(part, 10).toStrin…

1019hw

登录窗口头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QToolBar> #include <QMenuBar> #include <QPushButton> #include <QStatusBar> #include <QLabel> #include <QDockWidget>//浮动窗口…

node+vue+mysql后台管理系统

千千博客系统&#xff0c;该项目作为一套多功能的后台框架模板&#xff0c;适用于绝大部分的后台管理系统开发。基于 vue.js&#xff0c;使用 vue-cli3 脚手架&#xff0c;引用 Element UI 组件库&#xff0c;数据库直连mysql方便开发快速简洁好看的组件。 功能包含如下&#…

UGUI交互组件InputField

一.InputField的结构 对象说明InputField挂有TextMeshPro-InputField组件的主体对象Text Area文本显示区Placeholder未输入时占位文本Enter text...Text输入的显示文本 二.InputField的属性 属性说明Text ViewportText Area子对象的引用Text ComponentText子对象的引用Text输入…

OpenP2P实现内网穿透远程办公

OpenP2P是一个开源、免费、轻量级的P2P共享网络。你的设备将组成一个私有P2P网络&#xff0c;里面的设备可以直接访问其它成员&#xff0c;或者通过其它成员转发数据间接访问。如果私有网络无法完成通信&#xff0c;将会到公有P2P网络寻找共享节点协助通信。 相比BT网络用来共享…

IOday8

#include <head.h>//要发送数据的结构体类型 struct msgbuf {long mtype; /* 消息类型*/char mtext[1024]; /* 正文数据 */}; //宏定义正文大小 #define SIZE sizeof(struct msgbuf)-sizeof(long) int main(int argc, const char *argv[]) {key_t key;if((keyft…

为什么产品经理都要考NPDP?

最近很多宝子问我&#xff0c;产品经理适合考什么证书&#xff1f;那必然是NPDP啊&#xff01;作为国际产品专业认证&#xff0c;NPDP证书是现如今最炙手可热且含金量相对较高的证书了&#xff0c;下面胖圆讲给大家详细介绍一下NPDP证书的具体信息。 1&#xff09;NPDP是什么&…

Simulink 最基础教程(三)常用模块

3.1源模块 1&#xff09;clock 这个模块的输出是 y(t)t。很多信号都是和时间 t 相关的&#xff0c;例如正弦波信号&#xff0c;可以写成 sin(w*t) 的形式。虽然软件也提供了正弦波模块&#xff0c;但如果用 clock 模块三角运算模块&#xff0c;对初学者而言&#xff0c;也是很好…

​蔚来自动驾驶,从 2020 年开始讲起的故事

2020 年底&#xff0c;摆脱 2019 年阴霾的李斌先生&#xff0c;热情而兴奋&#xff0c;再一次说&#xff1a;「欢迎来到蔚来日。」 那天蔚来发布了令人咋舌的智能驾驶硬件系统&#xff0c;4 块当时甚至还没有宣布量产日期的 Orin 芯片&#xff0c;11 路高清摄像头。 早在 ET7…

云服务器ip使用细节(公网、私有)

场景&#xff1a; 当我们对tcp服务器进行监听的时候&#xff0c;可能需要用到ip地址&#xff0c;比如使用httplib::Service::listen(ip, port)&#xff0c;而当我们访问tcp服务器时也需要ip地址 但这两个ip是不同的&#xff01; 每个云服务器通常都会有一个公网IP地址和一个私有…

jQuery

1.jQuery概述 1.jQuery介绍 jQuery 是一个 JavaScript 库 框架&#xff1a;Mybatis &#xff08;jar包&#xff09; 大工具 插件&#xff1a;PageHelper &#xff08;jar包&#xff09; 小工具 库&#xff1a;js库&#xff1a;jquery (js文件) 小工具 &#xff08;对于原生…

Linux进阶-ipc共享内存

目录 共享内存 shmget()&#xff1a;创建或获取共享内存 shmat()&#xff1a;映射 shmdt()&#xff1a;解除映射 shmctl()&#xff1a;获取或设置属性 sem.h文件 sem.c文件 shm.c文件 Makefile文件 执行过程 共享内存 共享内存&#xff1a;将内存进行共享&#xff0c…

纯css+js自制下拉框

前提 因为html的select标签&#xff0c;下拉框自定义程度非常的低&#xff0c;为了贴合而项目ui显示&#xff0c;所以打算自制下拉框 代码 html <div class"pos-rel"><div id"select" class"select get-select"><span class&…

小程序中如何使用自定义组件应用及搭建个人中心布局

一&#xff0c;自定义组件 从小程序基础库版本 1.6.3 开始&#xff0c;小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。 开发者可以将页面内的功能模块抽象成自定义组件&#xff0c;以便在不同的页面中重复使用&#xff1b;也可以将复杂的…