[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

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、