freeRTOS总结(十)消息 队列

news2024/9/28 15:27:50

1,队列简介(了解)

队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递)
与全局变量的区别

类似全局变量?假设有一个全局变量a = 0,现有两个任务都在写这个变量a

在这里插入图片描述
在这里插入图片描述
假如 当任务1在进行数据交换前被任务2打断那么任务2运行完a的值多加了1任务1再运行加1则多加了1
全局变量的弊端:数据无保护,导致数据不安全,当多个任务同时对该变量操作时,数据易受损
FreeRTOS基于队列, 实现了多种功能,其中包括队列集、互斥信号量、计数型信号量、
二值信号量、 递归互斥信号量,因此很有必要深入了解 FreeRTOS 的队列 。
使用队列的情况如下: 读写队列做好了保护,防止多任务同时访问冲突;我们只需要直接调用API函数即可,简单易用!
在这里插入图片描述
在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据叫做“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度
在这里插入图片描述
1、队列长度为:5个
2、队列项目大小为:10字节
在创建队列时,就要指定队列长度以及队列项目的大小!
FreeRTOS队列特点:
1、数据入队出队方式:队列通常采用“先进先出”(FIFO)的数据存储缓冲机制,即先入队的数据会先从队列中被读取,FreeRTOS中也可以配置为“后进先出”LIFO方式;
2、数据传递方式:FreeRTOS中队列采用实际值传递,即将数据拷贝到队列中进行传递, FreeRTOS采用拷贝数据传递,也可以传递指针,所以在传递较大的数据的时候采用指针传递
3、多任务访问:队列不属于某个任务,任何任务和中断都可以向队列发送/读取消息
4、出队、入队阻塞:当任务向一个队列发送消息时,可以指定一个阻塞时间,假设此时当队列已满无法入队

若阻塞时间为0 :直接返回不会等待;
若阻塞时间为0~port_MAX_DELAY :等待设定的阻塞时间,若在该时间内还无法入队,超时后直接返回不再等待;
若阻塞时间为port_MAX_DELAY :死等,一直等到可以入队为止。出队阻塞与入队阻塞类似;
在这里插入图片描述
问题:当多个任务写入消息给一个“满队列”时,这些任务都会进入阻塞状态,也就是说有多个任务 在等待同一 个队列的空间。那当队列中有空间时,哪个任务会进入就绪态?
答:
1、优先级最高的任务
2、如果大家的优先级相同,那等待时间最久的任务会进入就绪态
** 队列操作基本过程**
在这里插入图片描述

2,队列结构体介绍(熟悉)

typedef struct QueueDefinition 
{
    int8_t * pcHead					/* 存储区域的起始地址 */
    int8_t * pcWriteTo;        				/* 下一个写入的位置 */
    union
    {
        	QueuePointers_t     xQueue; 
	SemaphoreData_t  xSemaphore; 
    } u ;
    List_t xTasksWaitingToSend; 			/* 等待发送列表 */
    List_t xTasksWaitingToReceive;			/* 等待接收列表 */
    volatile UBaseType_t uxMessagesWaiting; 	/* 非空闲队列项目的数量 */
    UBaseType_t uxLength;			/* 队列长度 */
    UBaseType_t uxItemSize;                 		/* 队列项目的大小 */
    volatile int8_t cRxLock; 				/* 读取上锁计数器 */
    volatile int8_t cTxLock;			/* 写入上锁计数器 */
   /* 其他的一些条件编译 */
} xQUEUE;

补充知识
union是一种特殊的数据结构,它允许在同一内存位置存储不同类型的数据。在C语言中,union可以包含多个成员,每个成员可以是不同的数据类型。但是,union只能同时使用一个成员。

union的定义方式和结构体类似,使用union关键字,并在花括号内定义成员。例如:

c
union Data {
int i;
float f;
char str[20];
};
上面的代码定义了一个名为Data的union,它有三个成员:一个整型变量i,一个浮点型变量f,和一个字符数组str。

union在内存中的大小等于最大成员的大小。这是因为union的所有成员共享同一块内存,而且只能同时使用一个成员。当修改union的某个成员时,其他成员的值会被覆盖。

union常用于需要在不同数据类型之间进行转换或节省内存空间的情况。但需要注意的是,在使用union时要确保对成员的访问是合法的,避免出现类型错误和未定义行为。

队列结构体整体示意图:
在这里插入图片描述

3,队列相关API函数介绍(掌握)

使用队列的主要流程:创建队列  写队列  读队列。
创建队列相关API函数介绍:
在这里插入图片描述
动态和静态创建队列之间的区别:队列所需的内存空间由 FreeRTOS 从 FreeRTOS 管理的堆中分配,而静态创建需要用户自行分配内存。

#define xQueueCreate (  uxQueueLength,   uxItemSize  )   						 \						
	   xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), (queueQUEUE_TYPE_BASE )) 

此函数用于使用动态方式创建队列,队列所需的内存空间由 FreeRTOS 从 FreeRTOS 管理的堆中分配
在这里插入图片描述
在这里插入图片描述
FreeRTOS 基于队列实现了多种功能,每一种功能对应一种队列类型,队列类型的 queue.h 文件中有定义:

#define queueQUEUE_TYPE_BASE                  			( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                  			( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX                 			( ( uint8_t ) 1U )	/* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE    	( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE     	( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX       		( ( uint8_t ) 4U )	/* 递归互斥信号量 */

在这里插入图片描述

#define  xQueueSend(  xQueue,   pvItemToQueue,   xTicksToWait  )	 					\    
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define  xQueueSendToBack(  xQueue,   pvItemToQueue,   xTicksToWait  )					 \    
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define  xQueueSendToFront(  xQueue,   pvItemToQueue,   xTicksToWait  ) 					\   
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
#define  xQueueOverwrite(  xQueue,   pvItemToQueue  ) 								\    
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )

队列一共有 3 种写入位置 :

#define queueSEND_TO_BACK                     	( ( BaseType_t ) 0 )		/* 写入队列尾部 */
#define queueSEND_TO_FRONT                    	( ( BaseType_t ) 1 )		/* 写入队列头部 */
#define queueOVERWRITE                        		( ( BaseType_t ) 2 )		/* 覆写队列*/

注意:覆写方式写入队列,只有在队列的队列长度为 1 时,才能够使用

BaseType_t     xQueueGenericSend(  QueueHandle_t 	xQueue,	const void * const 	pvItemToQueue,TickType_t xTicksToWait,const BaseType_t 	xCopyPosition   );

在这里插入图片描述
在这里插入图片描述
从队列读取消息API函数:
在这里插入图片描述

BaseType_t    xQueueReceive( QueueHandle_t   xQueue,  void *   const pvBuffer,  TickType_t   xTicksToWait )

此函数用于在任务中,从队列中读取消息,并且消息读取成功后,会将消息从队列中移除。
在这里插入图片描述
在这里插入图片描述

BaseType_t   xQueuePeek( QueueHandle_t   xQueue,   void * const   pvBuffer,   TickType_t   xTicksToWait )

此函数用于在任务中,从队列中读取消息, 但与函数 xQueueReceive()不同,此函数在成功读取消息后,并不会移除已读取的消息!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );


#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t   task1_handler;
void task1( void * pvParameters );


#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t   task2_handler;
void task2( void * pvParameters );

#define TASK3_PRIO         4
#define TASK3_STACK_SIZE   128
TaskHandle_t   task3_handler;
void task3( void * pvParameters );
QueueHandle_t g_key_queue_handle,g_big_date_queue_handle;
char g_buff[100] = {"我是一个大数组,大大的数组 124214 uhsidhaksjhdklsadhsaklj"};


/******************************************************************************************************/


/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{ 
/*********************************创建队列*********************************************************************/
 g_key_queue_handle  = xQueueCreate( 2, sizeof(uint8_t));
 if(g_key_queue_handle!=NULL)
 {
	 printf("key_queue队列创建成功!!\r\n");
 
 }else printf("key_queue队列创建失败!!\r\n");
	g_big_date_queue_handle = xQueueCreate( 1, sizeof(char *) );
  if(g_big_date_queue_handle!=NULL)
 {
	 printf("big_date_queue队列创建成功!!\r\n");
 
 }else printf("big_date_queue队列创建失败!!\r\n");
		
	xTaskCreate((TaskFunction_t) start_task,
							(char *)	"start_task",
							(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) START_TASK_PRIO,
							(TaskHandle_t *)&start_task_handler
	
	);
							
	//开启任务调度
	vTaskStartScheduler();
	
}
void start_task( void * pvParameters )
{
	 taskENTER_CRITICAL();               /* 进入临界区  任何任务和中断都不能打断当前程序运行*/
		xTaskCreate((TaskFunction_t) task1,
							(char *)	"task1",
							(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK1_PRIO,
							(TaskHandle_t *)&task1_handler	);
							
		xTaskCreate((TaskFunction_t) task2,
							(char *)	"task2",
							(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK2_PRIO,
							(TaskHandle_t *)&task2_handler	);
			xTaskCreate((TaskFunction_t) task3,
							(char *)	"task3",
							(configSTACK_DEPTH_TYPE) TASK3_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK3_PRIO,
							(TaskHandle_t *)&task3_handler	);
	vTaskDelete(NULL);//删除当前任务也就是开始任务
	taskEXIT_CRITICAL();
							
	

}

/* 任务一,实现入队 */
void task1( void * pvParameters )
{
	uint8_t key=0;
	char * buf;
	buf = g_buff; /* buf = &buff[0] */
	BaseType_t err;
		while(1)
		{
			key=key_scan(0);
			if(key==KEY0_PRES||key==KEY1_PRES)
			{
				err=xQueueSend(g_key_queue_handle,&key,portMAX_DELAY);
				if(err!=pdTRUE)
				{
					  printf("key_queue队列发送失败\r\n");
				}
			}
			else if(key == WKUP_PRES)
			{
				err = xQueueSend( g_big_date_queue_handle, &buf, portMAX_DELAY );
				if(err != pdTRUE)
            {
                printf("big_date_queue队列发送失败\r\n");
            }
			}
		
		vTaskDelay(10);
		}
}


void task2( void * pvParameters )
{
	    uint8_t key = 0;
    BaseType_t err = 0;

	while(1)
	{
		err = xQueueReceive( g_key_queue_handle,&key,portMAX_DELAY);
        if(err != pdTRUE)
        {
            printf("key_queue队列读取失败\r\n");
        }else 
        {
            printf("key_queue读取队列成功,数据:%d\r\n",key);

	}

}
	}
void task3( void * pvParameters )
{
    char * buf;
    BaseType_t err = 0;
    while(1)
    {
        err = xQueueReceive( g_big_date_queue_handle,&buf,portMAX_DELAY);
        if(err != pdTRUE)
        {
            printf("big_date_queue队列读取失败\r\n");
        }else 
        {
           printf("数据:%s\r\n",buf);
        }
    }
}

这里注意一个问题 队列项 的读取和写入参数中的第二个参数都是一个指向任意类型的指针所以我们这里key要取地址 ,同理大队列中队列项是大数组的首地址,所以将他的首地址给临时变量buf 再对buf进行取值写入和读取。

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

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

相关文章

三层架构-pc通外网小实验

要求:pc端能上外网(isp) 效果图:pc1(VLAN2)和pc3(vlan3)都能ping通2.2.2.2(R2环回) 代码:#先配置好r1,r2,端口ip # [R1] ip route-static 0.0.0.0 0.0.0.0 10.1.1.2 acl 2000 rule permit source any interface GigabitEthernet0/0/2 nat outbound 2000 …

Android消息推送 SSE(Server-Sent Events)方案实践

转载请注明出处:https://blog.csdn.net/kong_gu_you_lan/article/details/135777170 本文出自 容华谢后的博客 0.写在前面 最近公司项目用到了消息推送功能,在技术选型的时候想要找一个轻量级的方案,偶然看到一篇文章讲ChatGPT的对话机制是基…

Bank_Code_FullName_2020.06.16.xlsx

Bank_Code_FullName_2020.06.16.xlsx 银行联行号和全称 https://download.csdn.net/download/spencer_tseng/88780566 144692条记录,没法子贴上去

抖音VR直播:沉浸式体验一键打通360度精彩

随着5G技术的发展,VR直播近年来也逐步进入到大众的视野中,相比于传统直播,VR直播能够提供更加丰富的内容和多样化的互动方式,让观众更有沉浸感和参与感。现如今,抖音平台也上线了VR直播,凭借沉浸式体验和有…

基于 pytorch-openpose 实现 “多目标” 人体姿态估计

前言 还记得上次通过 MediaPipe 估计人体姿态关键点驱动 3D 角色模型,虽然节省了动作 K 帧时间,但是网上还有一种似乎更方便的方法。MagicAnimate 就是其一,说是只要提供一张人物图片和一段动作视频 (舞蹈武术等),就可以完成图片…

【Kubernetes】深入了解Kubernetes(K8s):现代容器编排的引领者

欢迎来到英杰社区: https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区: https://bbs.csdn.net/topics/617897397 作者简介: 辭七七,目前大二,正在学习C/C,Java,Python等 作者主页&#xf…

JVM-初始JVM

什么是JVM JVM 全称是 Java Virtual Machine,中文译名 Java虚拟机。JVM 本质上是一个运行在计算机上的程序,他的职责是运行Java字节码文件。 Java源代码执行流程如下: JVM的功能 1 - 解释和运行 2 - 内存管理 3 - 即时编译 解释和运行 解释…

LeetCode.2865. 美丽塔 I

题目 题目链接 分析 闲谈:每次读 LeetCode 的题目描述都要费老大劲,o(╥﹏╥)o 题意:这个其实意思就是以数组的每一位作为最高点,这个点(数字)左右两边的数字都不能大于这个数字(可以等于),…

Qt基础-屏蔽qDebug()、qWarning()调试和警告消息

本文讲解Qt如何-屏蔽qDebug()、qWarning()调试和警告消息 在工程文件.pro里面添加 DEFINES QT_NO_WARNING_OUTPUT\ QT_NO_DEBUG_OUTPUT 如果只想Release版本的时候不打印: Release:DEFINES QT_NO_WARNING_OUTPUT\ QT_NO_DEBUG_OUTPUT 这样只是在Release版本…

想要透明拼接屏展现更加效果,视频源是技术活,尤其作为直播背景

随着科技的飞速发展,视频制作和显示技术也在不断进步。透明拼接屏视频作为一种新型的视频形式,在许多场合都得到了广泛的应用。尼伽小编将深入探讨透明拼接屏视频的制作过程、要求、清晰度,以及目前常作为直播背景的优势。 一、透明拼接屏视频…

Make.com的发送邮件功能已经登峰造极

make.com的发送邮件功能已经做到了登峰造极。 我给你个任务,让你发送个新邮件给谁谁,你一定想到SMTP服务器不就行了。 我给你第二个任务,我让你自动回复一个邮件,注意是回复。 做不到了吧~~!…

【3万字】modbus简易不简单的教程

🎖️Modbus简易不简单的教程 文章目录 🎖️Modbus简易不简单的教程🎫一、简介1.1 Modbus:工业通信的革命1.2 理解标准化通信1.3 Modbus协议的变体 🎀二、例程引入2.1 示例:使用01功能码读取灯的开关状态2.2…

电商一年挣100w的赚钱模型

现在有多少人还不知道电商具体应该怎么干,有多少人还是看了身边的朋友做电商挣钱了也跟着做了。然后做半天没做起来,然后就找各种原因,你看别人每天上架你也上架,别人开车你也开车,别人亏钱你也亏钱,别人赚…

dns被劫持怎么修复?6种常用修复方法解读

当遇到DNS被劫持的情况时,通常表现出来的症状是无法正常访问某些网站,或者访问被重定向到不正确的地址。DNS劫持可能是由于恶意软件、黑客活动或者ISP(Internet服务提供商)的问题导致的。 以下是修复DNS劫持的六种方法&#xff1…

Siamese network 孪生神经网络--一个简单神奇的结构

1.名字的由来 Siamese和Chinese有点像。Siam是古时候泰国的称呼,中文译作暹罗。Siamese也就是“暹罗”人或“泰国”人。Siamese在英语中是“孪生”、“连体”的意思,这是为什么呢? 十九世纪泰国出生了一对连体婴儿,当时的医学技术…

C# 实现 Word 加盖骑缝章效果

目录 实现效果 范例运行环境 Office DCOM 配置 设计实现 创建stamp图章类 电子章图片的计算与定位 旋转图片方法 总结 实现效果 在OA的自动化处理系统中,通过审批的最终节点,可能会对WORD文件加盖电子章,比如定位带有指定文字的Ra…

微软人工智能办公AI工具 Copilot Pro 11项 Copilot 功能

Copilot(曾用名 Bing Chat 和 Bing Chat Enterprise)在此期间成为了许多用户的日常AI伴侣,并在正式发布后将继续为用户提供AI驱动的网络聊天体验。 微软Copilot官方网址链接:Microsoft Copilot: 你的日常 AI 助手 Copilot详情&am…

密码强度效果

文章目录 一、第一种规则实现 总结如有启发&#xff0c;可点赞收藏哟~ 一、第一种 规则 先展示效果 具体规则 长度显最小8位需有字母大小写需有数字需有特殊字符&#xff08;暂无限制字符类型&#xff09; 实现 定义组件password-strength.vue <template><div …

Github 2024-01-24开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-24统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量TypeScript项目3Dart项目2非开发语言项目2Go项目1Rust项目1Shell项目1Dockerfile项目1Jupyter Notebook项目1J…

最佳的reCAPTCHA v2验证码解析器,使用API或扩展自动解析reCAPTCHA v2

最佳的reCAPTCHA v2验证码解析器&#xff0c;使用API或扩展自动解析reCAPTCHA v2 reCAPTCHA v2提出了一个严峻的挑战&#xff0c;需要先进的解决方案。在本文中&#xff0c;我们揭示了验证码解析技术的巅峰&#xff1a;Capsolver。这个卓越的解决方案涵盖了解决reCAPTCHA v2挑战…