队列是一种任务到任务、任务到中断、中断到任务数据交流的一种机制。在队列中可以存
储数量有限、大小固定的多个数据,队列中的每一个数据叫做队列项目,队列能够存储队列项
目的最大数量称为队列的长度,在创建队列的时候,就需要指定所创建队列的长度及队列项目
的大小。因为队列是用来在任务与任务或任务于中断之间传递消息的一种机制,因此队列也叫
做消息队列。
1. 数据存储
队列通常采用 FIFO(先进先出)的存储缓冲机制,当有新的数据被写入队列中时,永远都
是写入到队列的尾部,而从队列中读取数据时,永远都是读取队列的头部数据。但同时 FreeRTOS
的队列也支持将数据写入到队列的头部,并且还可以指定是否覆盖先前已经在队列头部的数据。
2. 多任务访问
队列不属于某个特定的任务,可以在任何的任务或中断中往队列中写入消息或者读取消息。
3. 队列读取阻塞
在任务从队列读取消息时,可以指定一个阻塞超时时间。如果任务在读取队列时,队列为
空,这时任务将根据指定的阻塞超时时间添加到阻塞态任务列表中进行阻塞,以等待队列中
有可用的消息。当有其他任务或中断将消息写入队列中,因等待队列而阻塞任务将会被添加到
就绪态任务列表中,并读取队列中可用的消息。如果任务因等待队列而阻塞的时间超过指定的
阻塞超时时间,那么任务也将自动被转移到就绪态任务列表中,但不再读取队列中的数据。
因为同一个队列可以被多个任务读取,因此可能会有多个任务因等待同一个队列,而被阻
塞,在这种情况下,如果队列中有可用的消息,那么也只能有一个任务会被解除阻塞并读取到消
息,并且会按照阻塞的先后和任务的优先级,决定应该解除哪一个队列读取阻塞任务。
4. 队列 写入阻塞
与队列读取一样,在任务往队列写入消息时,也可以指定一个阻塞超时时间。如果任务在
写入队列时,队列已经满了,这时任务将被根据指定的阻塞超时时间添加到阻塞态任务列表中
进行阻塞,以等待队列有空闲的位置可以写入消息。指定的阻塞超时时间为任务阻塞的最大时
间,如果在阻塞超时时间到达之前,队列有空闲的位置,那么队列写入阻塞任务将会解除阻塞,
并往队列中写入消息,如果达到指定的阻塞超时时间,队列依旧没有空闲的位置写入消息,那
么队列写入阻塞任务将会自动转移到就绪态任务列表中,但不会往队列中写入消息。因为同一个队列可以被多个任务写入,因此可有会有多个任务因等待统一个任务,而被阻塞,在这种情况下,如果队列中有空闲的位置,那么也之后一个任务会被解除阻塞并往队列中写入消息,并且会按照阻塞的先后和任务的优先级,决定应该解除哪一个队列写入阻塞任务。
在使用队列进行任务之间的“沟通交流”时,一个队列只允许任务间传递的消息为同一种
数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集。FreeRTOS
提供的队列集功能可以对多个队列进行“监听”,只要被监听的队列中有一个队列有有效的消息,
那么队列集的读取任务都可以读取到消息,如果读取任务因读取队列集而被阻塞,那么队列集
将解除读取任务的阻塞。使用队列集的好处在于,队列集可以是的任务可以读取多个队列中的
消息,而无需遍历所有待读取的队列,以确定具体读取哪一个队列。
//任务1往队列中写数据,任务2往队列中读数据
#include "freeRTOS_demo.h"
#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 );
QueueHandle_t data_queue;
void freertos_demo(void)
{
data_queue = xQueueCreate( 1, sizeof(char *) );
if(data_queue != NULL)
{
printf("success\r\n");
}
else
{
printf("fail\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 );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
void task1( void * pvParameters )
{
char * buf="abcdefg";
BaseType_t err = 0;
err = xQueueSend( data_queue, &buf, portMAX_DELAY );
if(err != pdTRUE)
{
printf("send err\r\n");
}
while(1)
{
}
}
void task2( void * pvParameters )
{
char * buf;
BaseType_t err = 0;
while(1)
{
err = xQueueReceive( data_queue,&buf,portMAX_DELAY);
if(err != pdTRUE)
{
printf("read err\r\n");
}
else
{
printf("读取数据:%s\r\n",buf);
}
}
}
//创建队列集,存放2个队列。任务1往两个队列中写数据,任务2读取队列集的数据
#include "freeRTOS_demo.h"
#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 );
QueueSetHandle_t queueset_handle;
QueueHandle_t queue1_handle;
QueueHandle_t queue2_handle;
void freertos_demo(void)
{
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(); /* 进入临界区 */
queueset_handle = xQueueCreateSet( 2 ); /* 创建队列集,可以存放2个队列 */
if(queueset_handle != NULL)
{
printf("队列集创建成功!!\r\n");
}
queue1_handle = xQueueCreate( 1, sizeof(uint8_t) );
queue2_handle = xQueueCreate( 1, sizeof(char *) );
xQueueAddToSet( queue1_handle,queueset_handle);
xQueueAddToSet( queue2_handle,queueset_handle);
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 );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
void task1( void * pvParameters )
{
uint8_t key = 0;
BaseType_t err = 0;
char *buf="abc";
err = xQueueSend( queue1_handle, &key, portMAX_DELAY );
if(err == pdPASS)
{
printf("往队列queue1_handle写入数据成功!!\r\n");
}
err = xQueueSend( queue2_handle, &buf, portMAX_DELAY );
if(err == pdPASS)
{
printf("往队列queue2_handle写入数据成功!!\r\n");
}
while(1)
{
}
}
void task2( void * pvParameters )
{
QueueSetMemberHandle_t member_handle;
uint8_t key;
char *buf;
while(1)
{
member_handle = xQueueSelectFromSet( queueset_handle,portMAX_DELAY);
if(member_handle == queue1_handle)
{
xQueueReceive( member_handle,&key,portMAX_DELAY);
printf("获取到的队列1数据为:%d\r\n",key);
}
else if(member_handle == queue2_handle)
{
xQueueReceive( member_handle,&buf,portMAX_DELAY);
printf("获取到的队列2数据为:%s\r\n",buf);
}
}
}