[嵌入式RTOS专精]CMSIS-RTOS : 消息队列传输自定义的带数组结构体

CMSIS-RTOS的消息队列及内存池

使用CMSIS-RTOS: FreeRTOS的消息队列及内存池实现了传输自定义的结构体变量

为什么要使用"内存池"这类内存管理模块?

对于消息队列来说, 要想传输结构体变量, 只能使用传入指针的方式来进行实现

如:

typedef struct JsonPackage{
   
   
    int counter;
    char JsonString[128];
} t_JsonPackage;

	t_JsonPackage *JsonPtr = osPoolAlloc(JsonQ_Mem);
	/*
	* 或者使用 
	* t_JsonPackage *JsonPtr = (t_JsonPackage *)malloc(sizeof(t_JsonPackage));
	*/
	osMessagePut(JsonQueueHandle, (uint32_t)JsonPtr, 0);

若是没有对此指针指向的内存区进行内存管理, 则会产生大量不可控的内存碎片, 有运行时的内存隐患

CMSIS-RTOS对内存的管理进行了统一化, 预先创建好需要的内存池, 将对应的指针变量分配进内存池之中, 便能够安全有效地进行内存的管理与控制

在接收sender发送出的指针, 并完成对应处理后, 便可调用对应的API来销毁这部分不需要的内存.

	osPoolFree(JsonQ_Mem, JsonBuffer);

对应模块的初始化

首先定义内存池及消息队列的属性及对应句柄

//必须是全局变量!
osPoolDef(JsonQ_Mem, 16, t_JsonPackage);
osMessageQDef(JsonQueue, 16, uint32_t);
osPoolId JsonQ_Mem;
osMessageQId JsonQueueHandle;

//创建于其他函数调用内存池/消息队列之前
JsonQ_Mem = osPoolCreate(osPool(JsonQ_Mem));
JsonQueueHandle = osMessageCreate(osMessageQ(JsonQueue), NULL);

这里的句柄必须要是全局变量! 并且在需要调用的地方要extern进去

原因很简单, 最浅显的原因就是, 不这样做的话, osMessagePut或osMessageGet函数无法正常传参

较为深层的原因更容易让人理解, 即: 若是内存池的地址是随机变化的, 那我们自然无法在一个"变化不停"的内存片上进行管理

从代码层次上来看, 链表的头自然不可以乱动.

消息队列的发送与接收

<think>我们正在处理用户关于在CMSIS-RTOS中定义和创建消息队列对象的问题。根据站内引用,特别是引用[2]和[3],我们可以总结出以下步骤: 1. **定义消息结构体**:首先需要定义要通过消息队列传输的数据的结构体。例如,如果要传输一个包含数组结构体,我们可以这样定义: ```c typedef struct { char data[50]; // 假设我们有一个字符数组 int length; } CustomMessage; ``` 2. **创建内存池(如果需要传输自定义结构体)**:在CMSIS-RTOS中,如果要传输自定义结构体(非基本类型),通常需要创建一个内存池来管理这些结构体的内存。这是因为消息队列在传递消息时,实际上传递的是指向数据的指针,因此需要确保数据在传递过程中持久存在(通常通过内存池分配的内存块)。 使用`osPoolDef`宏定义内存池属性,然后使用`osPoolCreate`创建内存池。 ```c // 定义内存池属性:名称为MyMemPool,大小为16个元素,元素类型为CustomMessage osPoolDef(MyMemPool, 16, CustomMessage); // 创建内存池并获取句柄 osPoolId mem_pool = osPoolCreate(osPool(MyMemPool)); ``` 3. **定义消息队列属性并创建消息队列**:使用`osMessageQDef`宏定义消息队列属性(队列名称、队列大小、存储的消息类型)。注意,在CMSIS-RTOS中,消息队列存储的是`uint32_t`类型的数据。因此,如果我们要传递自定义结构体的指针,需要将其转换为`uint32_t`(因为指针可以转换为32位整数)。然后使用`osMessageCreate`创建消息队列。 ```c // 定义消息队列属性:名称为MyQueue,队列大小为16,存储的消息类型为uint32_t(即指针) osMessageQDef(MyQueue, 16, uint32_t); // 创建消息队列并获取句柄 osMessageQId queue_handle = osMessageCreate(osMessageQ(MyQueue), NULL); ``` 4. **使用消息队列发送和接收消息**: - **发送消息**: 首先从内存池中分配一块内存(用于存放自定义结构体),填充数据,然后将这块内存的指针作为消息发送(转换为`uint32_t`)。 ```c // 分配内存 CustomMessage *msg = (CustomMessage *)osPoolAlloc(mem_pool); // 填充数据 strcpy(msg->data, "Hello"); msg->length = 5; // 发送消息(将指针转换为uint32_t) osMessagePut(queue_handle, (uint32_t)msg, osWaitForever); ``` - **接收消息**: 接收消息时,获取到的是`uint32_t`类型的值,将其转换回指针,然后处理数据。处理完后,释放内存池中的内存。 ```c osEvent evt = osMessageGet(queue_handle, osWaitForever); if (evt.status == osEventMessage) { CustomMessage *msg = (CustomMessage *)evt.value.v; // 处理消息 // ... // 释放内存 osPoolFree(mem_pool, msg); } ``` 注意:如果传输的是基本数据类型(例如整数),则可以直接发送而不需要内存池。但是,对于较大的或自定义结构体,使用内存池是推荐的方式,以避免数据在栈上被覆盖。 根据引用[3]中的示例,他们定义了一个内存池和一个消息队列,然后创建它们。需要注意的是,这些定义(内存池和消息队列的句柄)必须是全局变量,以便在多个任务中访问。 总结步骤: 1. 定义消息结构体(如果需要传递复杂数据)。 2. 定义内存池(如果需要传递自定义结构体)并创建。 3. 定义消息队列并创建。 4. 在发送消息时,从内存池分配内存,填充数据,发送指针(转换为uint32_t)。 5. 在接收消息时,获取指针,处理数据,然后释放内存。 现在,我们可以将这些步骤整理成一个清晰的回答。 </think>### CMSIS-RTOS中定义和创建消息队列的方法 在CMSIS-RTOS中定义和创建消息队列需要遵循以下步骤,结合内存池管理保证数据传输的可靠性: #### 一、定义消息结构体(必需步骤) 首先声明需要通过队列传输自定义数据结构: ```c typedef struct { uint8_t data[50]; // 自定义数据数组 uint32_t length; // 数据长度标记 } t_MessagePackage; // 消息包结构体类型[^3] ``` #### 二、创建内存池(动态分配基础) 1. **定义内存池属性** 使用`osPoolDef`宏指定内存池参数: ```c #define osFeature_Pool 1 // 启用内存池功能[^2] osPoolDef(MsgPool, 16, t_MessagePackage); // 内存池名 | 容量 | 存储类型 ``` - `16`:预分配内存块数量 - `t_MessagePackage`:步骤一定义的结构体类型 2. **实例化内存池** 在全局作用域创建内存池实例: ```c osPoolId MsgPool = osPoolCreate(osPool(MsgPool)); // 返回内存池句柄[^3] ``` #### 三、定义并创建消息队列 1. **设置队列属性** 使用`osMessageQDef`宏配置队列: ```c osMessageQDef(MsgQueue, 16, uint32_t); // 队列名 | 深度 | 元素类型 ``` - `uint32_t`类型用于存储内存块指针(固定要求) 2. **创建消息队列实例** 在RTOS内核启动后初始化队列: ```c /* 包含头文件 */ #include "cmsis_os.h" /* 创建队列 */ osMessageQId MsgQueueHandle = osMessageCreate( osMessageQ(MsgQueue), // 引用队列定义 NULL // 无属性参数 )[^1][^3]; ``` - 返回`osMessageQId`类型句柄用于后续操作 #### 四、队列操作示例 ```c /* 发送消息 */ t_MessagePackage *tx_pkg = osPoolAlloc(MsgPool); // 申请内存块 tx_pkg->length = 10; // 填充数据 osMessagePut(MsgQueueHandle, (uint32_t)tx_pkg, osWaitForever); /* 接收消息 */ osEvent event = osMessageGet(MsgQueueHandle, osWaitForever); if(event.status == osEventMessage) { t_MessagePackage *rx_pkg = (t_MessagePackage *)event.value.v; osPoolFree(MsgPool, rx_pkg); // 释放内存块 } ``` #### 关键注意事项 1. **内存管理** 必须通过内存池分配消息空间,直接传递栈变量会导致数据失效[^3] 2. **数据类型约束** 队列元素必须是`uint32_t`类型,用于承载内存块指针 3. **作用域要求** 内存池和队列句柄需定义为**全局变量**(多任务共享访问)[^3] 4. **创建顺序** 先创建内存池 → 再创建消息队列(依赖关系) > 此方法适用于传输复杂数据结构(如图像帧、传感器数据包等),简单数据类型(如整型)可直接传递无需内存池[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值