在实际的应用中,常常会遇到一个任务或者中断服务需要和另外一个任务进行“沟通交流”,这个“沟通交流”的过程其实就是消息传递的过程。在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式,但是如果在使用操作系统的应用中用全局变量来传递消息就会涉及到“资源管理”的问题。FreeRTOS对此提供了一个叫做“队列”的机制来完成任务与任务、任务与中断之间的消息传递。本章我们就来学习FreeRTOS队列,本章分为如下几部分:
13.1队列简介
13.2队列结构体
13.3队列创建
13.4向队列发送消息
13.5队列上锁和解锁
13.6从队列读取消息
13.7队列操作实验
13.1队列简介队列
是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息,队列中可以存储有限的、大小固定的数据项目。任务与任务、任务与中断之间要交流的数据保存在队列中,叫做队列项目。队列所能保存的最大数据项目数量叫做队列的长度,创建队列的时候会指定数据项目的大小和队列的长度。由于队列用来传递消息的,所以也称为消息队列。FreeRTOS中的信号量的也是依据队列实现的!所以有必要深入的了解FreeRTOS的队列。
13.3队列创建
13.3.1函数原型
在使用队列之前必须先创建队列,有两种创建队列的方法,一种是静态的,使用函数xQueueCreateStatic();另一个是动态的,使用函数xQueueCreate()。这两个函数本质上都是宏,真正完成队列创建的函数是xQueueGenericCreate()和xQueueGenericCreateStatic(),这两个函数在文件queue.c中有定义,这四个函数的原型如下。
1、函数xQueueCreate()此函数本质上是一个宏,用来动态创建队列,此宏最终调用的是函数xQueueGenericCreate(),函数原型如下:
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,UBaseType_t uxItemSize)
uxQueueLength:要创建的队列的队列长度,这里是队列的项目数。
uxItemSize:队列中每个项目(消息)的长度,单位为字节
其他值:队列创捷成功以后返回的队列句柄!
NULL:队列创建失败。
2、函数xQueueCreateStatic()
此函数也是用于创建队列的,但是使用的静态方法创建队列,队列所需要的内存由用户自行分配,此函数本质上也是一个宏,此宏最终调用的是函数xQueueGenericCreateStatic(),函数原型如下:
QueueHandle_t xQueueCreateStatic(UBaseType_t uxQueueLength,UBaseType_t uxItemSize,uint8_t *pucQueueStorageBuffer,StaticQueue_t *pxQueueBuffer)
uxQueueLength:要创建的队列的队列长度,这里是队列的项目数。
uxItemSize:队列中每个项目(消息)的长度,单位为字节
pucQueueStorage:指向队列项目的存储区,也就是消息的存储区,这个存储区需要用户自行分配。此参数必须指向一个uint8_t类型的数组。这个存储区要大于等于(uxQueueLength * uxItemsSize)字节。
pxQueueBuffer:此参数指向一个StaticQueue_t类型的变量,用来保存队列结构体。
其他值:队列创捷成功以后的队列句柄!
NULL:队列创建失败。
3、函数xQueueGenericCreate()函数
xQueueGenericCreate()用于动态创建队列,创建队列过程中需要的内存均通过FreeRTOS中的动态内存管理函数pvPortMalloc()分配,
函数原型如下:QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_tuxItemSize, const uint8_t ucQueueType )
uxQueueLength:要创建的队列的队列长度,这里是队列的项目数。
uxItemSize:队列中每个项目(消息)的长度,单位为字节。
ucQueueType:队列类型,由于FreeRTOS中的信号量等也是通过队列来实现的,创建信号量的函数最终也是使用此函数的,因此在创建的时候需要指定此队列的用途,也就是队列类型,一共有六种类型:
queueQUEUE_TYPE_BASE普通的消息队列
queueQUEUE_TYPE_SET队列集
queueQUEUE_TYPE_MUTEX互斥信号量
queueQUEUE_TYPE_COUNTING_SEMAPHORE计数型信号量
queueQUEUE_TYPE_BINARY_SEMAPHORE二值信号量
queueQUEUE_TYPE_RECURSIVE_MUTEX递归互斥信号量函数
xQueueCreate()创建队列的时候此参数默认选择的就是queueQUEUE_TYPE_BASE。
其他值:队列创捷成功以后的队列句柄!
NULL:队列创建失败。
4、函数xQueueGenericCreateStatic()
此函数用于动态创建队列,创建队列过程中需要的内存需要由用户自行分配好,函数原型如下:
QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType )
uxQueueLength:要创建的队列的队列长度,这里是队列的项目数。
uxItemSize:队列中每个项目(消息)的长度,单位为字节
pucQueueStorage:指向队列项目的存储区,也就是消息的存储区,这个存储区需要用户自行分配。此参数必须指向一个uint8_t类型的数组。这个存储区要大于等于(uxQueueLength * uxItemsSize)字节。
pxStaticQueue:此参数指向一个StaticQueue_t类型的变量,用来保存队列结构体。
ucQueueType:队列类型。
其他值:队列创捷成功以后队列句柄!
NULL:队列创建失败。
/按键消息队列的数量
#define KEYMSG_Q_NUM 1 //按键消息队列的数量 (1)
#define MESSAGE_Q_NUM 4 //发送数据的消息队列的数量(2)
QueueHandle_t Key_Queue; //按键值消息队列句柄
QueueHandle_t Message_Queue;//信息队列句柄
// (1)、队列Key_Queue用来传递按键值的,也就是一个u8变量,所以队列长度为1就行了。并且消息长度为1个字节。
//(2)、队列Message_Queue用来传递串口接收到的数据,队列长度设置为4,每个消息的长度为USART_REC_LEN(在usart.h中有定义)。
//创建消息
Key_QueueKey_Queue=xQueueCreate(KEYMSG_Q_NUM,sizeof(u8)); (1)//创建消息Message_Queue,队列项长度是串口接收缓冲区长度
Message_Queue=xQueueCreate(MESSAGE_Q_NUM,USART_REC_LEN);(2)
//task1任务函数
void task1_task(void *pvParameters)
{
u8 key,i=0;
BaseType_t err;
while(1)
{
key=KEY_Scan(0); //扫描按键
if((Key_Queue!=0)&&(key)) //消息队列Key_Queue创建成功,并且按键被按下
{
err=xQueueSend(Key_Queue,&key,10);(3)
if(err==errQUEUE_FULL) //发送按键值
{
printf("队列Key_Queue已满,数据发送失败!\r\n");
}
}
i++;
if(i%10==0)
check_msg_queue();//检Message_Queue队列的容量(4)
if(i==50)
{
i=0; LED0=!LED0;
}
vTaskDelay(10); //延时10ms,也就是10个时钟节拍
}
}