FreeRTOS学习笔记(8)(队列集)
本文总结了FreeRTOS中队列集的使用方法。针对多任务系统中队列资源浪费问题,提出使用队列集解决方案。详细介绍了三个关键函数:xQueueCreateSet()创建队列集、xQueueAddToSet()添加队列到集合、xQueueSelectFromSet()读取队列数据。通过示例代码展示了如何创建三个队列(x/y/num)并加入队列集,在RX_task中使用队列集接收数据并在OLED上显示。
我这几张都是我学习韦东山老师的FreeRTOS课程所做的笔记,如果觉得内容又缺陷可以去老师的100ask网上看原版内容
言归正传,上一章学习了队列,但是我们所创造的队列只能完成当前任务,可移植性不高。那我偶们要怎么解决移植性问题呢,答案就是最后的程序运行部分全部都由一个大任务来完成,读取数据和解算的部分都由一个个小人物来完成。但是这样就没有问题了吗,每一个小任务的生成,都需要一部分栈空间,如果我们由太多任务,就会浪费资源,那我们就没有方法解决了吗?
有的兄弟,有的。
那就是把读取放到一个任务中用轮询的方式读取(显然不太可取)
但是作为FreeRTOS学者我们就可以使用队列集的操作

大概就像这样,每次在写A或者B时就会把A或B的句柄写入队列集中,然后会按照路列集里句柄的顺序一次次读取相应队列内的数据
首先我们要创建队列集
要用到xQueueCreateSet()函数
QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength )
| 参数 | 说明 |
|---|---|
| uxQueueLength | 队列集长度,最多能存放多少个数据(队列句柄) |
| 返回值 | 非0:成功,返回句柄,以后使用句柄来操作队列NULL:失败,因为内存不足 |
这里参数的解释是直接填入队列集中队列的个数,但是我尝试侯没有成功运行我的程序,但是我把它改成内存大小就行了,问题暂时没找出,如果找出问题以后会解答,
其次要说明的是,这个函数的返回值是队列集的句柄所以我们要配合一个队列集句柄变量使用
下一步就是写队列集,也就是把队列写入队列集
用到的函数是xQueueAddToSet()
BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,
QueueSetHandle_t xQueueSet );
| 参数 | 说明 |
|---|---|
| xQueueOrSemaphore | 队列句柄,这个队列要加入队列集 |
| xQueueSet | 队列集句柄 |
| 返回值 | pdTRUE:成功pdFALSE:失败 |
这一步没什么大难度,只要一个一个队列套用这个函数就好了
最后我们要学习读这个队列
用到的函数是xQueueSelectFromSet()
QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
TickType_t const xTicksToWait );
| 参数 | 说明 |
|---|---|
| xQueueSet | 队列集句柄 |
| xTicksToWait | 如果队列集空则无法读出数据,可以让任务进入阻塞状态,xTicksToWait表示阻塞的最大时间(Tick Count)。如果被设为0,无法读出数据时函数会立刻返回;如果被设为portMAX_DELAY,则会一直阻塞直到有数据可写 |
| 返回值 | NULL:失败,队列句柄:成功 |
这个函数一般都是一直阻塞,但是他的返回值也是一个句柄,我们要用一个队列据句柄变量去接收他,接收之后我们要用接收的的句柄进行判断是那一个队列的数据,可以用switch,case或者多重if
下面是一个要展示,还是传递数据在OLED上显示,这里要提醒大家一下,有的时候,无法接收数或者接收的数据无发使用,可以尝试延长定时阻塞时间,
QueueHandle_t x_Handle;
QueueHandle_t y_Handle;
QueueHandle_t num_Handle;//定义队列句柄变量
int x = 1;
int y = 2;
int num =3;//初始化数据
QueueSetHandle_t QueueSetHandle_t_input;//定义队列集句柄变量
x_Handle = xQueueCreate(10,sizeof(int));
y_Handle = xQueueCreate(10,sizeof(int));
num_Handle = xQueueCreate(10,sizeof(int));//创建队列
QueueSetHandle_t_input = xQueueCreateSet( 3*sizeof(int) );//创建队列集
xQueueAddToSet(x_Handle,QueueSetHandle_t_input);
xQueueAddToSet(y_Handle,QueueSetHandle_t_input);
xQueueAddToSet(num_Handle,QueueSetHandle_t_input);//将队列写入队列集
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
xQueueSend(num_Handle,&num,0);
OLED_ShowString(4,1,"yes");
osDelay(7);
}
/* USER CODE END StartDefaultTask */
}
void TX_task(void *argument)
{
/* USER CODE BEGIN TX_task */
/* Infinite loop */
for(;;)
{
xQueueSend(x_Handle,&x,0);
osDelay(7);
}
/* USER CODE END TX_task */
}
void RX_task(void *argument)
{
/* USER CODE BEGIN RX_task */
QueueSetMemberHandle_t RX_data;
static int X_receive = 0;
static int Y_receive = 0;
static int NUM_receive = 0;
/* Infinite loop */
for(;;)
{
RX_data = xQueueSelectFromSet(QueueSetHandle_t_input,portMAX_DELAY);
if(x_Handle==RX_data)//判断接收句柄
{
xQueueReceive(x_Handle,&X_receive,0);
OLED_ShowNum(1,1,X_receive,1);
}
else if(y_Handle==RX_data)
{
xQueueReceive(y_Handle,&Y_receive,0);
OLED_ShowNum(2,1,Y_receive,1);
}
else if(num_Handle==RX_data)
{
xQueueReceive(num_Handle,&NUM_receive,0);
OLED_ShowNum(3,1,NUM_receive,1);
}
osDelay(7);
}
/* USER CODE END RX_task */
}
void make_task(void *argument)
{
/* USER CODE BEGIN make_task */
/* Infinite loop */
for(;;)
{
xQueueSend(y_Handle,&y,0);
osDelay(7);
}
/* USER CODE END make_task */
}
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)