FREERTOS学习笔记,队列管理一

本文介绍了FreeRTOS中队列的使用,包括数据存储、任务的入口、队列读写阻塞、xQueueCreate()、xQueueSendToBack()、xQueueReceive()等函数的用法,以及队列在多任务环境中的应用实例。通过队列,可以实现任务间的同步和通信,支持阻塞读写和超时机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据存储

队列可以存储有限大小,且数据类型固定的数据。队列所能存储的最大数据量称为队列的长度。队列的长度与队列里元素的大小在队列创建时就已固定。队列经常别用作为先进先出存储。
实现队列的功能可通过两种方法。
通过复制的方法:将要进入队列的数据复制到队列中。
通过指针的方式:将需要进入队列的数据的指针放到队列中。

FREERTOS采用复制的方式进行队列数据的存储。

任务的入口

队列可以被知道队列存在的任一任务和中断读写。任一任务可以向同一个队列读写数据,一般情况下,一个队列具有较多写者,但不会有太多读者。

队列读者的阻塞

当一个任务尝试从一个队列中读数据时,可以可选的采用进入阻塞的方式,直到可以从该队列中读到数据。当任务处于读数据的阻塞状态时,一旦队列中有了数据,此时任务会自动从阻塞态转到就绪态。如果设定了超时时间,则在时间超时后任务依旧会自动从阻塞态转到就绪态。
队列一般有多个读者,则当有多个读者任务处于阻塞状态时,一旦有数据来临,则优先级最高的读者任务会先读数据,若读者任务优先级相同,则等待时间最长的任务会先读数据。

队列写者的阻塞

与读队列类似,写者也可以采用指定一个阻塞时间方式进入阻塞状态等待可以写数据或阻塞时间超时。

队列的使用

xQueueCreate()

创建队列,该函数用于创建一个队列并返回队列的句柄,当执行该函数时,该系统会从系统堆栈中分配一部分内存给该队列。其函数原型如下:

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );

相关参数:
uxQueueLength:用于表示该队列的长度。
uxItemSize :表示队列中每个数据的大小。
return value :表明创建的队列的句柄,若为NULL则表示空间不足导致创建失败。

xQueueReset() :当队列创建后,可用该函数将队列复位成原来的刚生成时状态。

xQueueSendToBack()xQueueSendToFront()

前者用于将数据送到队列尾部,后者用于将数据送到队列头部。xQueueSend()与前者完全相同。

注意:永远不要在中断中使用上述两种写队列的方法。在中断中有专门的写队列函数:xQueueSendToFrontFromISR() 与xQueueSendToBackFromISR()。后面会有相关讲解。

函数原型如下所示:

BaseType_t xQueueSendToFront( QueueHandle_t xQueue,
const void * pvItemToQueue,
TickType_t xTicksToWait );
BaseType_t xQueueSendToBack( QueueHandle_t xQueue,
const void * pvItemToQueue,
TickType_t xTicksToWait );

参数讲解:
xQueue:表明了队列的句柄。

pvItemToQueue:将要复制到队列中的数据的地址。

xTicksToWait :表示进入阻塞状态所等待的最大时间。当FreeRTOSConfig.h中的INCLUDE_vTaskSuspend设置为1时,若该参数输入为portMAX_DELAY,则该函数会无限期等待,并不会超时。

返回值(return value):1,pdPASS表示成功将数据写入队列。2,errQUEUE_FULL:表示在设置的时间内并没有将数据写进去。

xQueueReceive()

该函数用于从队列中读取一个数据,一旦读取之后,该值就会从队列中清除掉。通写数据,在中断中不可调用该函数,中断中有相应函数。
函数原型如下:

BaseType_t xQueueReceive( QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait );

输入参数同往队列中写数据
返回值:1,bdPASS,2errQUEUE_EMPTY

uxQueueMessagesWaiting()

用于查询队列中已经存储了多少数据。
注意:在中断中不可调用该函数,中断中有专门函数。

函数原型如下:

UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue );

输入参数为队列的句柄,输出为队列中数据的个数,返回0表示队列为空。

从队列中阻塞读数据实例

这个例子主要展示了创建一个队列,以及从队列中读写数据。写队列的优先级低于读队列的优先级。这表明,一旦往队列中写了数据后,队列的任务会马上退出阻塞态抢占处理器从而读取队列,之后写任务有可往里面写数据。

往队列写数据的任务函数如下:

static void vSenderTask( void *pvParameters )
{ 
	int32_t lValueToSend;
	BaseType_t xStatus;
	/* Two instances of this task are created so the value that is sent to the
	queue is passed in via the task parameter - this way each instance can use
	a different value. The queue was created to hold values of type int32_t,
	so cast the parameter to the required type. */
	lValueToSend = ( int32_t ) pvParameters;
	/* As per most tasks, this task is implemented within an infinite loop. */
	for( ;; )
	{
		/* Send the value to the queue.
		The first parameter is the queue to which data is being sent. The
		queue was created before the scheduler was started, so before this task
		started to execute.
		The second parameter is the address of the data to be sent, in this case
		the address of lValueToSend.
		The third parameter is the Block time – the time the task should be kept
		in the Blocked state to wait for space to become available on the queue
		should the queue already be full. In this case a block time is not
		specified because the queue should never contain more than one item, and
		therefore never be full. */
		xStatus = xQueueSendToBack( xQueue, &lValueToSend, 0 );
		if( xStatus != pdPASS )
		{
			/* The send operation could not complete because the queue was full -
			this must be an error as the queue should never contain more than
			one item! */
			vPrintString( "Could not send to the queue.\r\n" );
		}
	}
}

从队列中读数据的任务函数如下:

static void vReceiverTask( void *pvParameters )
{
	/* Declare the variable that will hold the values received from the queue. */
	int32_t lReceivedValue;
	BaseType_t xStatus;
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100 );
	/* This task is also defined within an infinite loop. */
	for( ;; )
	{
		/* This call should always find the queue empty because this task will
		immediately remove any data that is written to the queue. */
		if( uxQueueMessagesWaiting( xQueue ) != 0 )
		{
			vPrintString( "Queue should have been empty!\r\n" );
		}
		/* Receive data from the queue.
		The first parameter is the queue from which data is to be received. The
		queue is created before the scheduler is started, and therefore before this
		task runs for the first time.
		The second parameter is the buffer into which the received data will be
		placed. In this case the buffer is simply the address of a variable that
		has the required size to hold the received data.
		The last parameter is the block time – the maximum amount of time that the
		task will remain in the Blocked state to wait for data to be available
		should the queue already be empty. */
		xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait );
		if( xStatus == pdPASS )
		{
		/* Data was successfully received from the queue, print out the received
		value. */
			vPrintStringAndNumber( "Received = ", lReceivedValue );
		}
		else
		{
			/* Data was not received from the queue even after waiting for 100ms.
			This must be an error as the sending tasks are free running and will be
			continuously writing to the queue. */
			vPrintString( "Could not receive from the queue.\r\n" );
		}
	}
}

主函数内容如下:

QueueHandle_t xQueue;
int main( void )
{
	/* The queue is created to hold a maximum of 5 values, each of which is
	large enough to hold a variable of type int32_t. */
	xQueue = xQueueCreate( 5, sizeof( int32_t ) );
	if( xQueue != NULL )
	{
		/* Create two instances of the task that will send to the queue. The task
		parameter is used to pass the value that the task will write to the queue,
		so one task will continuously write 100 to the queue while the other task
		will continuously write 200 to the queue. Both tasks are created at
		priority 1. */
		xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL );
		xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL );
		/* Create the task that will read from the queue. The task is created with
		priority 2, so above the priority of the sender tasks. */
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL );
		/* Start the scheduler so the created tasks start executing. */
		vTaskStartScheduler();
	}
	else
	{
	/* The queue could not be created. */
	}
	/* If all is well then main() will never reach here as the scheduler will
	now be running the tasks. If main() does reach here then it is likely that
	there was insufficient FreeRTOS heap memory available for the idle task to be
	created. Chapter 2 provides more information on heap memory management. */
	for( ;; );
}

该函数可以看出一共创建了一个队列,三个任务,两个写任务一个读队列任务,写任务优先级均为1,读任务优先级为2。
执行结果如下所示:
在这里插入图片描述
进程调度图如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值