[FreeRTOS 功能应用] 互斥访问与回环队列 功能应用

2024-06-23 09:52

本文主要是介绍[FreeRTOS 功能应用] 互斥访问与回环队列 功能应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一、基础知识点
    • 二、代码讲解
    • 三、结果演示
    • 四、代码下载


一、基础知识点

[FreeRTOS 基础知识] 互斥访问与回环队列 概念
[FreeRTOS 内部实现] 互斥访问与回环队列
[FreeRTOS 内部实现] 创建任务 xTaskCreate函数解析

本实验是基于STM32F103开发移植FreeRTOS实时操作系统,实现多任务同时读写队列数据操作。
使用工具:Keil、串口工具


二、代码讲解

1、使用xQueueCreate函数 创建队列。

// 路径:项目\Core\Src\freertos.c
// 全局变量
QueueHandle_t g_xQueue;/* 创建队列,长度5,数据大小4个字节 */
g_xQueue = xQueueCreate(5, sizeof(int32_t));

2、使用osThreadCreate创建三个任务
两个任务Sender1、Sender2负责将数据写入队列,一个任务Seceiver从队列中取出数据。

// 路径:项目\Core\Src\freertos.c
// 全局变量
osThreadId Sender1_Handle;
osThreadId Sender2_Handle;
osThreadId Seceiver_Handle;if ( g_xQueue != NULL ){// 创建两个任务,传入参数100,200osThreadDef(Sender1, vSendTask, osPriorityNormal, 0, 1000);Sender1_Handle = osThreadCreate(osThread(Sender1), (void *)100);if( Sender1_Handle != NULL ){printf("Succeeded in creating Sender1_Handle Queue. Procedure!\n\r");}else{printf("Fail in creating Sender1_Handle Queue. Procedure!\n\r");}osThreadDef(Sender2, vSendTask, osPriorityNormal, 0, 100);Sender2_Handle = osThreadCreate(osThread(Sender2), (uint32_t *)200);if( Sender2_Handle != NULL ){printf("Succeeded in creating Sender2_Handle Queue. Procedure!\n\r");}else{printf("Fail in creating Sender2_Handle Queue. Procedure!\n\r");}osThreadDef(Seceiver, vSeceiverTask, osPriorityHigh, 0, 1000);Seceiver_Handle = osThreadCreate(osThread(Seceiver), NULL);        if( Seceiver_Handle != NULL ){printf("Succeeded in creating Seceiver_Handle Queue. Procedure!\n\r");}else{printf("Fail in creating Seceiver_Handle Queue. Procedure!\n\r");}        
}

函数中通过osThreadDef 宏构建osThreadDef_t 结构体,名称os_thread_def_##name(## 表示字符拼接),结构体成员包括 :#name 任务名称;thread 任务处理函数;priority 任务优先级;instances 实例; stacksz 栈大小;

#define osThreadDef(name, thread, priority, instances, stacksz)  \
const osThreadDef_t os_thread_def_##name = \
{ #name, (thread), (priority), (instances), (stacksz), NULL, NULL }

将构建的osThreadDef_t 结构体传入osThreadCreate函数中,实际调用xTaskCreate函数创建任务。

osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)
{TaskHandle_t handle;if (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),&handle) != pdPASS)  {return NULL;} return handle;
}

注:Sender1、Sender2任务函数共用一个。

3、Sender1、Sender2 任务函数vSendTask 实现
Sender1、Sender2负责将数据写入队列。由于两个任务使用一个任务处理函数,因此在处理函数内部要先区分当前运行的是哪任务,这里使用任务句柄:每个任务在创建时都会返回一个任务句柄( TaskHandle_t ),这个句柄可以用来唯一标识一个任务。可以在任务函数中使用 xTaskGetCurrentTaskHandle() 函数获取当前任务的句柄,然后与已知的任务句柄进行比较。
pcTaskGetTaskName() 函数来获取当前任务的名称。这个名称是在任务创建时指定的,因此可以用来区分不同的任务。

void vSendTask(void const * argument)
{/* USER CODE BEGIN StartDefaultTask */BaseType_t xReturn = pdPASS;   /* 定义一个创建信息返回值,默认为pdPASS */int32_t lValueToSend;/* Infinite loop */for(;;){/* 根据任务句柄执行不同的任务逻辑,也可以使用参数传入的方式区分任务 */TaskHandle_t xTaskHandle = xTaskGetCurrentTaskHandle();  /* 获取当前任务名称 */const char *pcTaskName = pcTaskGetName(xTaskHandle);lValueToSend = ( int32_t ) argument;xReturn = xQueueSend( g_xQueue, &lValueToSend, 0 ); if (pdPASS == xReturn)printf("DWB Sent SUCCESS ---> %s Message %d sent successfully! \n\r",pcTaskName ,(uint32_t)argument);elseprintf("DWB Sent FAIL ---> %s Message %d sent Fail! \n\r",pcTaskName, (uint32_t)argument);vTaskDelay(pdMS_TO_TICKS(600));   // 延时600ms}    
}

在这个示例中, 使用 xTaskGetCurrentTaskHandle() 来获取当前任务的句柄,然后调用 pcTaskGetTaskName() 来获取任务名称,并将其打印出来。这样,每次任务执行时,都会打印出当前是哪个任务在运行。
注, pcTaskGetTaskName() 函数需要FreeRTOS的配置宏 configUSE_TRACE_FACILITY 被定义为1,以便启用任务跟踪和任务名称的功能。如果你的FreeRTOS配置没有启用这个宏,你需要先在FreeRTOSConfig.h中定义它。

多个任务使用一个任务函数,在任务函数中还可以使用下面几个方法实现

  1. 使用任务优先级:如果每个任务的优先级不同,可以在任务函数中通过 uxTaskPriorityGet(NULL) 获取当前任务的优先级,然后根据优先级执行不同的逻辑。
  2. 使用全局变量:可以定义一个全局变量数组,每个元素对应一个任务的状态或标识。在任务函数中,根据任务的某种标识访问对应的全局变量。
  3. 使用静态变量:在任务函数内部定义静态变量,每个任务实例都会有自己的静态变量副本,可以用来存储任务特定的信息。
  4. 使用事件组:如果任务需要根据事件来执行不同的逻辑,可以使用事件组( EventGroupHandle_t )来区分不同的事件,并在任务函数中根据事件执行相应的操作。
  5. 使用任务通知:通过发送和接收任务通知( vTaskNotifyGive() 和 ulTaskNotifyTake() ),任务可以在接收到特定通知时执行不同的逻辑。

4、Seceiver任务函数 vSeceiverTask实现
任务Seceiver从队列中取出数据。

void vSeceiverTask(void const * argument)
{BaseType_t xReturn = pdTRUE;   /* 定义一个创建信息返回值,默认为pdTRUE */uint32_t r_queue; /* 定义一个接收消息的变量 */const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );for(;;){xReturn = xQueueReceive( g_xQueue, &r_queue, xTicksToWait);      // 获取队列值         if (pdTRUE == xReturn)printf("DWB Receive SUCCESS ---> The data received is %d. \n",(uint32_t)r_queue);elseprintf("DWB Receive FAIL ---> Data reception error, error code :%ld. \n\r",xReturn);vTaskDelay(pdMS_TO_TICKS(500));   // 延时500ms}    
}

三、结果演示

通过串口工具查看,任务读写队列情况
在这里插入图片描述


四、代码下载

[FreeRTOS ] 互斥访问与回环队列 功能应用

这篇关于[FreeRTOS 功能应用] 互斥访问与回环队列 功能应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1086826

相关文章

亮相WOT全球技术创新大会,揭秘火山引擎边缘容器技术在泛CDN场景的应用与实践

2024年6月21日-22日,51CTO“WOT全球技术创新大会2024”在北京举办。火山引擎边缘计算架构师李志明受邀参与,以“边缘容器技术在泛CDN场景的应用和实践”为主题,与多位行业资深专家,共同探讨泛CDN行业技术架构以及云原生与边缘计算的发展和展望。 火山引擎边缘计算架构师李志明表示:为更好地解决传统泛CDN类业务运行中的问题,火山引擎边缘容器团队参考行业做法,结合实践经验,打造火山

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

Android我的二维码扫描功能发展史(完整)

最近在研究下二维码扫描功能,跟据从网上查阅的资料到自己勉强已实现扫描功能来一一介绍我的二维码扫描功能实现的发展历程: 首页通过网络搜索发现做android二维码扫描功能看去都是基于google的ZXing项目开发。 2、搜索怎么使用ZXing实现自己的二维码扫描:从网上下载ZXing-2.2.zip以及core-2.2-source.jar文件,分别解压两个文件。然后把.jar解压出来的整个c

自制的浏览器主页,可以是最简单的桌面应用,可以把它当成备忘录桌面应用

自制的浏览器主页,可以是最简单的桌面应用,可以把它当成备忘录桌面应用。如果你看不懂,请留言。 完整代码: <!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><ti

Python应用开发——30天学习Streamlit Python包进行APP的构建(9)

st.area_chart 显示区域图。 这是围绕 st.altair_chart 的语法糖。主要区别在于该命令使用数据自身的列和指数来计算图表的 Altair 规格。因此,在许多 "只需绘制此图 "的情况下,该命令更易于使用,但可定制性较差。 如果 st.area_chart 无法正确猜测数据规格,请尝试使用 st.altair_chart 指定所需的图表。 Function signa

气象站的种类和应用范围可以根据不同的分类标准进行详细的划分和描述

气象站的种类和应用范围可以根据不同的分类标准进行详细的划分和描述。以下是从不同角度对气象站的种类和应用范围的介绍: 一、气象站的种类 根据用途和安装环境分类: 农业气象站:专为农业生产服务,监测土壤温度、湿度等参数,为农业生产提供科学依据。交通气象站:用于公路、铁路、机场等交通场所的气象监测,提供实时气象数据以支持交通运营和调度。林业气象站:监测林区风速、湿度、温度等气象要素,为林区保护和

vue3项目将所有访问后端springboot的接口统一管理带跨域

vue3项目将所有访问后端springboot的接口统一管理带跨域 一、前言1.安装Axios2.创建Axios实例3.创建API服务文件4.在组件中使用API服务 二、跨域三、总结 一、前言 在Vue 3项目中,统一管理所有访问后端Spring Boot接口的最佳实践是创建一个专门的API服务层。这可以让你的代码更加模块化、可维护和集中管理。你可以使用Axios库作为HTT

开启青龙 Ninja 扫码功能失效后修改成手动填写CK功能【修正Ninja拉库地址】

国内:进入容器docker exec -it qinglong bash #获取ninjagit clone -b main https://ghproxy.com/https://github.com/wjx0428/ninja.git /ql/ninja#安装cd /ql/ninja/backend && pnpm install cp .env.example .env

PyTorch模型_trace实战:深入理解与应用

pytorch使用trace模型 1、使用trace生成torchscript模型2、使用trace的模型预测 1、使用trace生成torchscript模型 def save_trace(model, input, save_path):traced_script_model = torch.jit.trace(model, input)<