1.队列概念
1)队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递)
2)队列类似数组,只能存储有限数量、相同类型的数据,在创建时需指定队列长度与队列项大小
3)出队入队阻塞:
若阻塞时间为0 :直接返回不会等待;
若阻塞时间为0~port_MAX_DELAY :等待设定的阻塞时间,若在该时间内还无法入队,超时后直接返回不再等待;
若阻塞时间为port_MAX_DELAY :死等,一直等到可以入队为止。出队阻塞与入队阻塞类似;
4)数据传递方式:FreeRTOS中队列采用实际值传递,即将数据拷贝到队列中进行传递, FreeRTOS采用拷贝数据传递,也可以传递指针,所以在传递较大的数据的时候采用指针传递
2.队列结构体
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;
3队列相关API函数介绍
3.1 创建队列
xQueueCreate() 动态创建
xQueueCreateStatic() 静态创建
实际调用xQueueGenericCreate()
#define xQueueCreate ( uxQueueLength, uxItemSize ) \
xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), (queueQUEUE_TYPE_BASE ))
返回值: NULL 创建失败
其他值 创建成功
注意队列类型6种:
#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) /* 队列 /
#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) / 队列集 /
#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) / 互斥信号量 /
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) / 计数型信号量 /
#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) / 二值信号量 /
#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) / 递归互斥信号量 */
3.2 队列写入消息API函数
调用函数xQueueGenericSend( ),只是指定了不同的写入位置有三种位置如下:
#define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) /* 写入队列尾部 /
#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 ) / 写入队列头部 /
#define queueOVERWRITE ( ( BaseType_t ) 2 ) / 覆写队列*/
xQueueGenericSend( QueueHandle_t xQueue, //待写入队列
const void * const //待写入消息
pvItemToQueue, //阻塞超时时间
TickType_t xTicksToWait, //写入位置
返回值: pdTRUE 队列写入成功
errQUEUE_FULL 队列写入失败
3.3 从队列读取消息API函数
BaseType_t xQueueReceive( QueueHandle_t xQueue, //带读取队列
void * const pvBuffer, //信息读取缓冲区
TickType_t xTicksToWait ) //阻塞超时时间
返回值: pdTRUE 读取成功
errQUEUE_FULL 读取失败
4 队列实战
4.1 freertos_demo.c
#include "freertos_demo.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
//1任务 配置
//1.1START_TASK 任务 配置
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 */
//1.2TASK1 任务 配置
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler; /* 任务句柄 */
void task1(void *pvParameters); /* 任务函数 */
//1.3TASK2 任务 配置
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task2Task_Handler; /* 任务句柄 */
void task2(void *pvParameters); /* 任务函数 */
#define TASK3_PRIO 4
#define TASK3_STK_SIZE 128
TaskHandle_t task3_handler;
void task3( void * pvParameters );
//2 队列配置
QueueHandle_t key_queue; /* 小数据句柄 */
QueueHandle_t big_date_queue; /* 大数据句柄 */
char buff[100] = {"我是一个大数组,大大的数组 124214 uhsidhaksjhdklsadhsaklj"};
//2 freertos_demo函数中创建start_task1任务
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
//2 start_task函数中创建task1、task2任务
void start_task(void *pvParameters)
{
//2.2进入临界区
taskENTER_CRITICAL();
/* 队列的创建 */
key_queue = xQueueCreate( 2, sizeof(uint8_t) );
if(key_queue != NULL)
{
printf("key_queue队列创建成功!!\r\n");
}else printf("key_queue队列创建失败!!\r\n");
big_date_queue = xQueueCreate( 1, sizeof(char *) );
if(big_date_queue != NULL)
{
printf("big_date_queue队列创建成功!!\r\n");
}else printf("big_date_queue队列创建失败!!\r\n");
// 2.1创建任务1
xTaskCreate((TaskFunction_t )task1,
(const char* )"task1",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
// 2.2创建任务2
xTaskCreate((TaskFunction_t )task2,
(const char* )"task2",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
// 2.3创建任务3
xTaskCreate((TaskFunction_t )task3,
(const char* )"task3",
(uint16_t )TASK3_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK3_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler);
//退出临界区
taskEXIT_CRITICAL();
}
//3 task1实现入队
void task1(void *pvParameters)
{
int8_t key = 0;
char * buf;
BaseType_t err =0;
buf = &buff[0];
while (1)
{
key = key_scan(0);
if (key == KEY0_PRES || key == KEY1_PRES)
{
err = xQueueSend(key_queue, &key, portMAX_DELAY); /* 将键值作为消息发送到队列中 */
if(err != pdTRUE)
{
printf("key_queue发送失败\r\n");
}
}
else if(key == WKUP_PRES)
{
err = xQueueSend(big_date_queue,&buf, portMAX_DELAY); /* 将键值作为消息发送到队列中 */
if(err != pdTRUE)
{
printf("big_date_queue发送失败\r\n");
}
}
vTaskDelay(10);
}
}
//4 他上课小数据出队
void task2(void *pvParameters)
{
uint8_t key = 0; //接收从队列中的读取值
BaseType_t err = 0;
while(1)
{
err=xQueueReceive(key_queue,&key,portMAX_DELAY);
if(err != pdTRUE)
{
printf("key_queue读取失败\r\n");
}
else
{
printf("key_queue读取队列成功,数据:%d\r\n",key);
}
}
}
//5 大数据出队
void task3(void *pvParameters)
{
char* buf = 0; //接收从队列中的读取值
BaseType_t err = 0;
while(1)
{
err=xQueueReceive(big_date_queue,&buf,portMAX_DELAY);
if(err != pdTRUE)
{
printf("big_date_queue读取失败\r\n");
}
else
{
printf("数据:%s\r\n",buf);
}
}
}