FreeRTOS消息队列笔记(自用)

目录

xQueueCreate解析

Queue_t结构体

prvInitialiseNewQueue函数

xQueueGenericReset函数

xQueueCreate函数

xQueueSend解析

vTaskPlaceOnEventList和prvAddCurrentTaskToDelayedList函数

xQueueSend函数

xQueueReceive解析

xQueueGenericReceive函数


主要对xQueueCreate和xQueueSend以及xQueueReceive的解析,其余API不一一解析。

xQueueCreate解析

Queue_t结构体

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;		/* 存放队列锁定时一共有多少任务想发送队列消息 */
} xQUEUE;
typedef xQUEUE Queue_t;

prvInitialiseNewQueue函数

初始化新的消息队列

static void prvInitialiseNewQueue( 
const UBaseType_t uxQueueLength, //队列消息长度
const UBaseType_t uxItemSize,    //队列消息项大小
uint8_t *pucQueueStorage,        //队列存放消息的首地址
const uint8_t ucQueueType, 
Queue_t *pxNewQueue              //消息队列首地址( 消息队列 = 消息控制块 + 消息。所有这个地址就是消息控制块首地址 )
)
{
    ( void ) ucQueueType;   //防止编译出未使用变量警告
    if( uxItemSize == ( UBaseType_t ) 0 )
	{
		/* 没有消息长度,但不能设置成NULL,因为NULL会被认为是互斥锁 */
		pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
	}
	else	//
	{
		/* 指向消息队列的消息内存首地址 */
		pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;
	}

    /* 初始化队列长度和项大小 */
    pxNewQueue->uxLength = uxQueueLength;
	pxNewQueue->uxItemSize = uxItemSize;
    /* 初始化队列其他成员变量 */
    ( void ) xQueueGenericReset( pxNewQueue, pdTRUE );
}

xQueueGenericReset函数

将队列重新恢复到初始状态

/* 重置队列 */
BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )
{
    Queue_t * const pxQueue = ( Queue_t * ) xQueue;

    taskENTER_CRITICAL();
    {
        /* 指向消息队列的尾地址 */
        pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );
        /* 当前消息队列消息数为0 */
		pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
        /* 消息写入位置为,消息第一个项首地址 */
		pxQueue->pcWriteTo = pxQueue->pcHead;
        /* 消息读取位置为,消息最后一个项的地址 */
		pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );
		/* 都没锁 */
        pxQueue->cRxLock = queueUNLOCKED;
		pxQueue->cTxLock = queueUNLOCKED;

        if( xNewQueue == pdFALSE )//不是新创建的队列
        {
            if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )//发送消息等待队列不为空
            {
                if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
                {
                    queueYIELD_IF_USING_PREEMPTION();//调用一次pend,切换任务
                }
            }
        }
        else       //新创建的队列
		{
			/* 初始化队列 */
			vListInitialise( &( pxQueue->xTasksWaitingToSend ) );
			vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );
		}
    }
}

xQueueCreate函数

创建消息队列

#define xQueueCreate( uxQueueLength, uxItemSize ) \
xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )

QueueHandle_t xQueueGenericCreate( 
const UBaseType_t uxQueueLength, //队列长度
const UBaseType_t uxItemSize,   //队列项大小
const uint8_t ucQueueType       
)
{
    Queue_t *pxNewQueue;
	size_t xQueueSizeInBytes;
	uint8_t *pucQueueStorage;


    if( uxItemSize == ( UBaseType_t ) 0 )
    {
        /* 队列项大小为0,队列的消息所占字节为0 */
        xQueueSizeInBytes = ( size_t ) 0;
    }
    else
    {
        /* 计算队列消息所需要的字节数 */
        xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); 
    }
    /* 申请队列所需的内存,大小为队列控制块大小+队列的消息所占字节然后8字节对齐后的大小 */
    pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );

    if( pxNewQueue != NULL )
    {
        /* pucQueueStorage指向存放消息的首地址 */
        pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t );
        /* 初始化消息队列 */
        prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
    }
    return pxNewQueue;
}

xQueueSend解析

发送消息给消息队列

vTaskPlaceOnEventList和prvAddCurrentTaskToDelayedList函数

vTaskPlaceOnEventList将当前任务的实践列表项加入指定列表,并且将当前任务加入阻塞列表。

void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )
{
    vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );
	prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
}
static void prvAddCurrentTaskToDelayedList
( TickType_t xTicksToWait,  //阻塞时间
 const BaseType_t xCanBlockIndefinitely 
)
{
    TickType_t xTimeToWake;
    const TickType_t xConstTickCount = xTickCount;
    /* 将当前任务的任务状态列表项从当前列表删除 */
    if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
	{
		//更新uxTopReadyPriority变量(就绪列表的最高优先级)。
        portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
	}

    /* 阻塞时间为无限大,且xCanBlockIndefinitely不等于pdFALSE(等于pdFALSE一般表示无限期) */
    if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
    {
        /* 当前任务加入挂起列表而不是阻塞列表 */
        vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
    }
    else
    {
        /* 计算任务阻塞时长 */
        xTimeToWake = xConstTickCount + xTicksToWait;
        /* 更新xItemValue值,用于对任务在列表中的排序 */
        listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
        /* 节拍溢出,任务加入pxOverflowDelayedTaskList阻塞列表 */
        if( xTimeToWake < xConstTickCount )
        {
            /* Wake time has overflowed.  Place this item in the overflow
            list. */
            vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
        }
        else    //未溢出
        {
            /* 正常加入pxDelayedTaskList阻塞列表 */
            vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
            /* 任务阻塞时间比xNextTaskUnblockTime(记录着下一个任务解除阻塞的时间)小,更新 */
            if( xTimeToWake < xNextTaskUnblockTime )
            {
                xNextTaskUnblockTime = xTimeToWake;
            }
        }
    }

}

xQueueSend函数

#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) \
xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )


BaseType_t xQueueGenericSend
( 
    QueueHandle_t xQueue,               //队列句柄
    const void * const pvItemToQueue,   //发送的消息地址
    TickType_t xTicksToWait,            //阻塞时间
    const BaseType_t xCopyPosition      //发送模式
)
{
    BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
    TimeOut_t xTimeOut;
    Queue_t * const pxQueue = ( Queue_t * ) xQueue;

    for( ;; )
    {
        taskENTER_CRITICAL();
        {
            //队列长度未满或者覆盖模式
            if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
            {
                /* 将消息放入队列 */
                xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
                
                #else /* configUSE_QUEUE_SETS==0 无队列集功能 */
				{
					/* 检查是否有队列正在因为等待队列消息而排队 */
					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
					{
                        /* 将因等待队列而阻塞的最高任务优先级的任务从xTasksWaitingToReceive中删除,加入到就绪列表中 */
						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
						{
							/* 删除成功且任务优先级比当前任务高,执行一次pend任务切换 */
							queueYIELD_IF_USING_PREEMPTION();
						}
					}
					else if( xYieldRequired != pdFALSE )
					{
						/* 特例,互斥量使用 */
						queueYIELD_IF_USING_PREEMPTION();
					}
				}
				#endif /* configUSE_QUEUE_SETS */
                taskEXIT_CRITICAL();
			    return pdPASS;
            }
            else    //队列已满
            {
                if( xTicksToWait == ( TickType_t ) 0 )
                {
                    /* 无指定阻塞时间直接退出 */
                    taskEXIT_CRITICAL();
                    return errQUEUE_FULL;
                }
                else if( xEntryTimeSet == pdFALSE )
                {
                    /* 获取当前系统节拍信息 */
                    vTaskSetTimeOutState( &xTimeOut );
                    xEntryTimeSet = pdTRUE;
                }   
            }
        }
        taskEXIT_CRITICAL();

        /* 暂停所有任务 */
        vTaskSuspendAll();
        /* 锁定队列 */
        prvLockQueue( pxQueue );

        /* 检查任务超时 */
        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
        {
            if( prvIsQueueFull( pxQueue ) != pdFALSE )//队列还是满的
            {
                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );

                prvUnlockQueue( pxQueue );

                if( xTaskResumeAll() == pdFALSE )
				{
					portYIELD_WITHIN_API();
				}
            }else
            {
                prvUnlockQueue( pxQueue );
				( void ) xTaskResumeAll();
            }
        }
        else//已超时,返回发送失败
		{
			/* The timeout has expired. */
			prvUnlockQueue( pxQueue );
			( void ) xTaskResumeAll();

			traceQUEUE_SEND_FAILED( pxQueue );
			return errQUEUE_FULL;
		}
    }
}


xQueueReceive解析

获取消息的函数,会将读取的消息删除。

xQueueGenericReceive函数

#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )

BaseType_t xQueueGenericReceive
( 
    QueueHandle_t xQueue,//消息队列句柄
    void * const pvBuffer, //存放读取消息队列的内存的指针
    TickType_t xTicksToWait, // 最大阻塞时间 
    const BaseType_t xJustPeeking //读取后是否保留消息
)
{
    BaseType_t xEntryTimeSet = pdFALSE;
    TimeOut_t xTimeOut;
    int8_t *pcOriginalReadPosition;
    Queue_t * const pxQueue = ( Queue_t * ) xQueue;
    
    for( ;; )
    {
        taskENTER_CRITICAL();
        {
            const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;

            if( uxMessagesWaiting > ( UBaseType_t ) 0 )//队列不为空
            {
                pcOriginalReadPosition = pxQueue->u.pcReadFrom;//指向消息队列中要读取数据的内存
                prvCopyDataFromQueue( pxQueue, pvBuffer );//获取消息到pvBuffer

                if( xJustPeeking == pdFALSE )//会删除读取的消息
                {
                    pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;//消息数量减一
                    /* 因等待写入阻塞的任务列表不为空 */
                    if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
                    {
                        /* 删除发送阻塞任务中的任务,如果优先级高于当前任务,运行一次切换函数pend */
                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
                        {
                            queueYIELD_IF_USING_PREEMPTION();
                        }
                    }
                }
                else //不删除
                {
                    /* 将读取位置重新恢复 */
                    pxQueue->u.pcReadFrom = pcOriginalReadPosition;
                    /* 读取阻塞队列不为空 */
                    if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                    {
                        if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                        {
                            /* The task waiting has a higher priority than this task. */
                            queueYIELD_IF_USING_PREEMPTION();
                        }
                    }
                }
                taskEXIT_CRITICAL();
                return pdPASS;
            }
            else    //消息队列为空
            {
                if( xTicksToWait == ( TickType_t ) 0 )//阻塞时间为0,返回err
				{
					taskEXIT_CRITICAL();
					return errQUEUE_EMPTY;
				}
                else if( xEntryTimeSet == pdFALSE )//第一次循环的时候才可能进入
                {
                    vTaskSetTimeOutState( &xTimeOut );//获取系统节拍信息
					xEntryTimeSet = pdTRUE;
                }
            }
        }
        taskEXIT_CRITICAL();
        vTaskSuspendAll();  //调度器挂起
		prvLockQueue( pxQueue );//锁定队列
        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )//判断是否时间是否超时
        {
            if( prvIsQueueEmpty( pxQueue ) != pdFALSE )//队列是否为空
            {
                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
				prvUnlockQueue( pxQueue );
                if( xTaskResumeAll() == pdFALSE )//调度器重新启动
				{
					portYIELD_WITHIN_API();
				}
            }
        }
        else//超时
		{
			prvUnlockQueue( pxQueue );//解锁
			( void ) xTaskResumeAll();//开启调度器

			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )//消息队列还是为空,返回错误
			{
				return errQUEUE_EMPTY;
			}
		}
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值