赞
踩
使用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函数无法正常传参
较为深层的原因更容易让人理解, 即: 若是内存池的地址是随机变化的, 那我们自然无法在一个"变化不停"的内存片上进行管理
从代码层次上来看, 链表的头自然不可以乱动.
osMessagePut & osMessageGet
前文已说明了内存池的用处, 接下来就进入实战环节, 从代码的角度来感受用法
我这里实现的功能是, 接收到一个完整的Json数据串后, 将接收到的数据串传入消息队列之中, 然后在接收线程部分对其进行处理
//发送者 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){ if(huart == &huart3){ static int uart3_RxFlag, uart3_RxStatus; switch(uart3_RxStatus){ case 0: if(uart3Buffer[uart3_RxFlag] == UART_STARTFLAG){ uart3_RxFlag++; uart3_RxStatus = 1; }else{ memset(uart3Buffer, 0, sizeof(uart3Buffer)); } break; case 1: if(uart3Buffer[uart3_RxFlag] != UART_ENDFLAG){ uart3_RxFlag++; }else{ memset(&uart3Buffer[uart3_RxFlag + 1], 0, sizeof(uart3Buffer) - uart3_RxFlag); uart3_RxFlag = 0; uart3_RxStatus = 0; t_JsonPackage *JsonPtr = osPoolAlloc(JsonQ_Mem); memcpy(JsonPtr->JsonString, uart3Buffer, sizeof(uart3Buffer)); osMessagePut(JsonQueueHandle, (uint32_t)JsonPtr, 0); } break; default: break; } HAL_UART_Receive_IT(&huart3, (uint8_t*)&uart3Buffer[uart3_RxFlag], 1); } } //接收者 void UARTTask(void const *argument) { HAL_UART_Receive_IT(&huart3, (uint8_t*)&uart3Buffer, 1); osEvent JsonQueueEvt; //接收消息的句柄 t_JsonPackage *JsonBuffer = NULL; //这里不需要分配内存, 因为等下就要将内存池中的发送者指针地址赋值于此变量 for (;;) { JsonQueueEvt = osMessageGet(JsonQueueHandle, osWaitForever); //若是没有接收到消息, 则阻塞式等候 if(JsonQueueEvt.status == osEventMessage){ JsonBuffer = JsonQueueEvt.value.p; //获取发送者传入的结构体指针变量, 彻底完成消息的接收步骤 uart3_printf("buffer: %s\r\n", JsonBuffer->JsonString); osPoolFree(JsonQ_Mem, JsonBuffer); //处理完毕数据之后, 及时清理内存, 避免内存溢出 } } }
若UART的打印函数不加入互斥锁Mutex, 则在大批量打印请求时必定出现卡死的情况, 加入互斥锁后彻底解决。
osMutexDef(printfMutex); osMutexId printfMutex; void setup(){ printfMutex = osMutexCreate(osMutex(printfMutex)); //放于初始化函数中 } void uart3_printf(const char* format, ...) { osMutexWait(printfMutex, portMAX_DELAY); char buffer[64]; // 缓冲区用于存储格式化后的字符串 va_list args; va_start(args, format); vsnprintf(buffer, sizeof(buffer), format, args); // 格式化字符串到缓冲区 va_end(args); for (size_t i = 0; buffer[i] != '\0'; ++i) { HAL_UART_Transmit(&huart3, (uint8_t *) &buffer[i], 1, HAL_MAX_DELAY); } osMutexRelease(printfMutex); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
t_JsonPackage *JsonPtr = osPoolAlloc(JsonQ_Mem); memcpy(JsonPtr->JsonString, uart3Buffer, sizeof(uart3Buffer)); osMessagePut(JsonQueueHandle, (uint32_t)JsonPtr, 0);
- 1
- 2
- 3
在上述函数中, 有两个数组 JsonPtr->JsonString(char [128]) 与 uart3Buffer[128] 数组
无法直接使用类似"JsonPtr->JsonString = uart3Buffer"或"“JsonPtr->JsonString = &uart3Buffer[0]”"的赋值式
应使用memcpy(JsonPtr->JsonString, uart3Buffer, sizeof(uart3Buffer));
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。