一、队列简介
- 队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递)
- 使用队列的情况下如图,在写、读队列时,会进入临界区,无法触发任务调度,不会出现多任务冲突,只需要调用API函数即可
- 在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据叫做“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度
- 队列采用先进先出(FIFO)的数据存储缓冲机制,即先入队的数据会先从队列中被读取,FreeRTOS也可以配置成先进后出的方式
- FreeRTOS中队列采用实际值传递,或传递地址
- 任何任务和中断都可以向队列发送/读取消息
- 当任务向一个队列发送消息时,可以指定一个阻塞时间,设置阻塞时间,确定是否等待或者返回
- 当任务A写入队列时,队列已满的情况下,可以将该任务挂在阻塞列表或等待发送列表。当任务B从队列读取数据时,队列无数据的情况下,将任务挂在阻塞列表或等待接收列表里
二、队列相关函数
2.1 队列结构体
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;
2.2 队列相关API函数
- 使用队列时,主要流程为:创建队列 -> 写队列 -> 读队列
- 创建队列相关API函数
xQueueCreate();
xQueueCreateStatic();
#define xQueueCreate(uxQueueLength,uxItemSize)
xQueueGenericCreate( (uxQueueLength),(uxItemSize),(queueQUEUE_TYPE_BASE) )
xQueueSend();
xQueueSendToBack();
xQueueSendToFront();
xQueueOverwrite();
xQueueSendFromISR();
xQueueSendToBackFromISR();
xQueueSendToFrontFromISR();
xQueueOverwriteFromISR();
#define 函数名 xQueueGenericSend((xQueue),(pvItemToQueue),(xTicksToWait),位置)
#define queueSEND_TO_BACK ((BaseType_t)0)
#define queueSEND_TO_FRONT ((BaseType_t)1)
#define queueOVERWRITE ((BaseType_t)2)
xQueueReceive();
xQueuePeek();
xQueueReceiveFromISR();
xQueuePeekFromISR();
BaseType_t xQueueReceive(QueueHandle_t xQueue,void *const pvBuffer,TickType_t xTicksToWait)
BaseType_t xQueuePeek(QueueHandle_t xQueue,void *const pvBuffer,TickType_t xTicksToWait)
三、队列操作实验
- 创建四个任务
- start_task:创建task1、task2和task3
- task1:当按键key0或key1按下,将按键键码拷贝到队列key_queue(入队),当key2按下,将传输大数据,拷贝大数据内容到队列big_data_queue里
- task2:读取队列key_queue中的消息(出队),打印出接收的键值
- task3:从队列big_data_queue读取大数据地址,通过地址访问大数据
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define INCLUDE_vTaskSuspend 1
#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t start_task_handle;
#define TASK1_STACK_SIZE 128
#define TASK1_PRIO 2
TaskHandle_t task1_handle;
#define TASK2_STACK_SIZE 128
#define TASK2_PRIO 3
TaskHandle_t task2_handle;
#define TASK3_STACK_SIZE 128
#define TASK3_PRIO 4
TaskHandle_t task3_handle;
QueueHandle_t key_queue;
QueueHandle_t big_key_queue;
char buff[] = "hello world";
void task1( void * pvParameters )
{
uint8_t KeyNum = 0;
char *buf;
buf = buff;
BaseType_t err = 0;
while(1)
{
KeyNum = Key_GetNum();
if(KeyNum==0 || KeyNum==1)
{
err = xQueueSend(key_queue,&KeyNum,portMAX_DELAY);
}
else if(KeyNum == 2)
{
err = xQueueSend(big_date_queue,&buf,portMAX_DELAY);
}
vTaskDelay(10);
}
}
void task2( void * pvParameters )
{
uint8_t KeyNum = 0;
BaseType_t err = 0;
while(1)
{
err = xQueueReceive(key_queue,&keyNum,portMAX_DELAY);
}
}
void task3( void * pvParameters )
{
char *buf;
BaseType_t err = 0;
while(1)
{
err = xQueueReceive(big_date_queue,&buf,portMAX_DELAY);
}
}
void Start_task( void * pvParameters )
{
taskENTER_CRITICAL();
xTaskCreate(task1,
"task1",
TASK1_STACK_SIZE,
NULL,
TASK1_PRIO,
&task1_handle
);
xTaskCreate(task2,
"task2",
TASK2_STACK_SIZE,
NULL,
TASK2_PRIO,
&task2_handle
);
xTaskCreate(task3,
"task3",
TASK3_STACK_SIZE,
NULL,
TASK3_PRIO,
&task3_handle
);
vTaskDelete(start_task_handle);
taskEXIT_CRITICAL();
}
void freertos_demo()
{
key_queue = xQueueCreate(2,sizeof(uint8_t));
big_date_queue = xQueueCreate(1,sizeof(char*));
xTaskCreate(Start_task,
"Start_task",
START_TASK_STACK_SIZE,
NULL,
START_TASK_PRIO,
&start_task_handle
);
vTaskStartScheduler();
}