Day 5 :队列
队列的作用:用于任务与任务,任务与中断之间的通信,在认识队列之前首先确认一些基本常识:
- 队列中存储的数据,即任务之间交流的数据,成为队列项目;
- 队列长度是队列所能保存的最大数据项目数量;
- 数据的存储方式有两种:FIFO(先进先出)和LIFO(后进先出),字面意思,很好理解;
- 队列不属于任何一个任务,仅用于传递消息和数据;
- FreeRTOS有关于队列的代码都放在queue.c中;
1. 队列结构
typedef struct QueueDefinition
{
int8_t *pcHead; //指向队列开始地址
int8_t *pcTail; //指向队列存储区最后一个字节
int8_t *pcWriteTo; //指向存储区下一个空闲区域
union
{
int8_t *pcReadFrom; //指向最后一个出对的队列项首地址
UBaseType_t uxRecursiveCallCount; //用来记录地柜互斥量杯调用的次数
} 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; //队列上锁后入队队列项数目
//静态存储
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated;
#endif
//队列集相关宏
#if ( configUSE_QUEUE_SETS == 1 )
struct QueueDefinition *pxQueueSetContainer;
#endif
//跟踪调试相关宏
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxQueueNumber;
uint8_t ucQueueType;
#endif
} xQUEUE;
typedef xQUEUE Queue_t;
2.队列创建
和任务一样,创建方式有两种:动态和静态,分别是xQueueCreate( )和xQueueCreateStatic( );动态意味着内存由系统分配,静态意味着内存由用户分配。
xQueueCreate()和xQueueCreateStatic()本质是宏定义,真正的函数是 xQueueGenericCreate( )和xQueueGenericCreateStatic( );具体代码如下:
QueueHandle_t xQueueGenericCreate(
const UBaseType_t uxQueueLength, //队列长度
const UBaseType_t uxItemSize, //队列项长度,单位字节
const uint8_t ucQueueType //队列类型
)
{
Queue_t *pxNewQueue;
size_t xQueueSizeInBytes;
uint8_t *pucQueueStorage;
//队列长度必须大于0,断言,用于调试,若断言失败,则会卡在死循环里
configASSERT( uxQueueLength > ( UBaseType_t ) 0 );
if( uxItemSize == ( UBaseType_t ) 0 )
{
//队列项大小为0,不需要存储区
xQueueSizeInBytes = ( size_t ) 0;
}
else
{
//分配足够的存储区
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize );
}
//分配内存,大小是队列结构体+消息存储区
pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );
if( pxNewQueue != NULL ) //分配成功
{
//计算出消息存储区的首地址,队列结构体在前,存储区紧跟其后
pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t );
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
//动态创建方式需要标记队列字段
pxNewQueue->ucStaticallyAllocated = pdFALSE;
}
#endif
//初始化队列
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
}
return pxNewQueue; //返回队列句柄
}
当队列创建成功时,返回队列句柄,否则返回其他值;
QueueHandle_t xQueueGenericCreateStatic(
const UBaseType_t uxQueueLength, //队列长度
const UBaseType_t uxItemSize, //队列项长度,单位字节
uint8_t *pucQueueStorage, //指向队列存储区
StaticQueue_t *pxStaticQueue, //指向队列结构体
const uint8_t ucQueueType //队列类型
)
{
Queue_t *pxNewQueue;
//队列长度必须大于0、结构体必须存在等等
configASSERT( uxQueueLength > ( UBaseType_t ) 0 );
configASSERT( pxStaticQueue != NULL );
configASSERT( !( ( pucQueueStorage != NULL ) && ( uxItemSize == 0 ) ) );
configASSERT( !( ( pucQueueStorage == NULL ) && ( uxItemSize != 0 ) ) );
#if( configASSERT_DEFINED == 1 )
{
//没弄懂,猜测是确保静态创建的结构体大小等于实际队列结构体+信号量的大小