[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 ] 互斥访问与回环队列 功能应用

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

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

相关文章

解决WebStorm中不显示npm任务面板

鼠标右键项目的package.json文件,然后点击show npm scripts选项。 然后npm工具窗口就显示了:

02--MySQL数据库概述

目录 第10章 子查询 10.1 SELECT的SELECT中嵌套子查询 10.2 SELECT的WHERE或HAVING中嵌套子查询 10.3 SELECT中的EXISTS型子查询 10.4 SELECT的FROM中嵌套子查询 第11章 MySQL支持的数据类型 11.1 数值类型:包括整数和小数 1、整数类型 2、bit类型 3、小数类型 11.2…

【Python系列】探索 NumPy 中的 mean 函数:计算平均值的利器

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

软件串口接收子程序

代码; stduart.c /*《AVR专题精选》随书例程3.通信接口使用技巧项目:使用延时法实现半双工软件串口文件:sfuart.c说明:软件串口驱动文件作者:邵子扬时间:2012年12月13日*/ #include "sfduart.h"// 循环中延…

WinMerge v2 (开源的文件比较/合并工具)

前言 WinMerge 是一款运行于Windows系统下的免费开源的文件比较/合并工具,使用它可以非常方便地比较多个文档内容甚至是文件夹与文件夹之间的文件差异。适合程序员或者经常需要撰写文稿的朋友使用。 一、下载地址 下载链接:http://dygod/source 点击搜…

【Linux】进程间通信3——线程安全

1.Linux线程互斥 1.1.进程线程间的互斥相关背景概念 临界资源: 多线程执行流共享的资源叫做临界资源。临界区: 每个线程内部,访问临界资源的代码,就叫做临界区。互斥: 任何时刻,互斥保证有且只有一个执行…

动态创建接口地址

和SpringBoot版本有关系 这里用的boot 2.2.2

LabVIEW电控旋翼测控系统

开发基于LabVIEW开发的电控旋翼测控系统,通过高效监控和控制提升旋翼系统的性能和安全性。系统集成了多种硬件设备,采用模块化设计,实现复杂的控制和数据处理功能,适用于现代航空航天领域。 项目背景 传统旋翼系统依赖机械和液压…

IO模型详解

阻塞IO模型 假设应用程序的进程发起IO调用,但是如果内核的数据还没准备好的话,那应用程序进程就一直在阻塞等待,一直等到内核数据准备好了,从内核拷贝到用户空间,才返回成功提示,此次IO操作,称…

C# 中的静态关键字

C# 语言中的 static 关键字用于声明静态类和静态类成员。静态类和静态类成员(如构造函数、字段、属性、方法和事件)在只需要一个对象(类或类成员)副本并在类型(和成员)的所有实例(对象&#xff…

React+TS前台项目实战(十五)-- 全局常用组件Table封装

文章目录 前言Table组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 在这篇文章中,我们将对本系列项目中常用的表格组件Table进行自定义封装,以提高性能并适应项目需求。后期也可进行修改和扩展,以满足项目的需求。 Table组…

C# Onnx Yolov5 水果识别,人员识别,物品识别 人工智能

目录 先上效果 来电废话,但实用 网络成功案例实践易失败的原因 万物检测涉及技术 下载合集 关键代码 全部代码 实操vs2022安装关键 YOLO V5核心库编译 编写自己识别软件 更新相关依赖 标注字库文件 测试效果 名词解释YOLO 名词解释ONNX 源码 直播教…

卸载 ubuntu-wsl2-systemd-script,使用 WSLg 图形用户界面

目录 全新安装 - 以前没有安装 WSL现有 WSL 安装卸载 ubuntu-wsl2-systemd-script使用 Linux GUI参考链接在 Windows 上使用 Linux 开发环境,最好的做法是使用 WSL2。在 WSL 和早期的 WSL2 版本中,并不支持图形用户界面。因此如果想要使用 GUI 程序,需要自行解决。具体方法可…

读线圈和离散状态寄存器信息

一.功能码操作类型 二.读线圈状态 需求实例 读取设备地址为 3 的从设备的线圈状态寄存器,线圈地址为 19 到 55(从 0 开始计算)共 37 个状态。 分析:由需求可知读取地址,则功能码是0x01,地址为3即为0x03,线圈地址为19到…

Python | Leetcode Python题解之第179题最大数

题目&#xff1a; 题解&#xff1a; class Solution:def largestNumber(self, nums: List[int]) -> str:def quick_sort(l , r):if l > r: returni, j l, rwhile i < j:while strs[j] strs[l] > strs[l] strs[j] and i < j: j - 1while strs[i] strs[l] &l…

基于matlab的BP神经网络分类预测

1.神经网络结构 本文网络结构如图1所示&#xff1a; 图1 网络结构 图1给出的并不是单纯的bp神经网络结构这里设置了三个隐藏层&#xff0c;神经元个数分别为6&#xff0c;3&#xff0c;3&#xff0c;输入层12个特征输入&#xff0c;输出层输出4个类型结果。 2.代码 %% 清空环…

使用ViewDragHelper打造属于自己的DragLayout(抽屉开关 )

</com.xujun.drawerLayout.drag.DragLayout> 在代码中若想为其设置监听器, 分别可以监听打开的 时候&#xff0c;关闭的时候&#xff0c;拖动的时候&#xff0c;可以在里面做相应的处理&#xff0c;同时我还加入了 自定义属性可以通过 app:range”480”或者setRange&am…

嵌入式linux系统中LCD屏驱动实现思路分析

在 Linux 下 LCD 的使用更加广泛,在搭配 QT 这样的 GUI 库下可以制作出非常精美的 UI 界面。接下来就来学习一下如何在 Linux 下驱动 LCD 屏幕。 第一:Framebuffer设备简介 先来回顾一下裸机的时候 LCD 驱动是怎么编写的,裸机 LCD 驱动编写流程如下: ①、初始化 I.MX6U 的…

Selenium WebDriver - 网络元素

本文翻译整理自&#xff1a;https://www.selenium.dev/documentation/webdriver/elements/ 文章目录 一、文件上传二、定位策略1、传统定位器2、创建定位器3、类名4、CSS选择器5、id6、NAME7、链接文本8、部分链接文本9、标签名称10、xpath11、相对定位器它是如何工作的可用相对…

three.js 第八节 - gltf加载器、解码器

// ts-nocheck // 引入three.js import * as THREE from three // 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入hdr加载器&#xff08;专门加载hdr的&#xff09; import { RGBELoader } from three/examples/jsm/loaders…