freertos之队列的阻塞访问

1.概念

  1. 只要知道队列的句柄,谁都可以读、写该队列。任务、 ISR 都可读、写队列。可以多个任务读写队列。
  2. 任务读写队列时,简单地说:如果读写不成功,则阻塞;可以指定超时时间。如果能读写了就马上进入就绪态,否则就阻塞直到超时。
  3. 读取队列的任务个数没有限制,那么当多个任务读取空队列时,这些任务都会进入阻塞状态。写队列的任务个数没有限制,那么当多个任务写"满队列"时,这些任务都会进入阻塞状态。
  4. 有多个任务在等待同一个队列的数据。当队列中有数据时,哪个任务会进入
    就绪态?
    1. 优先级最高的任务
    2. 如果大家的优先级相同,那等待时间最久的任务会进入就绪态
  5. 有多个任务在等待同一个队列的空间。当队列中有空间时,哪个任务会进入就绪态?
    1. 优先级最高的任务
    2. 如果大家的优先级相同,那等待时间最久的任务会进入就绪态

2.阻塞程序

创建一个队列,然后创建 2 个发送任务、 1 个接收任务。
1. 创建的队列,用来发送结构体:数据大小是结构体的大小
2. 发送任务优先级为 2,接收任务优先级为 1。
3. 读队列、打印信息

main函数

/* 定义2种数据来源(ID) */
typedef enum
{
	eMotorSpeed,
	eSpeedSetPoint
} ID_t;

/* 定义在队列中传输的数据的格式 */
typedef struct {
    ID_t eDataID;
    int32_t lDataValue;
}Data_t;

/* 定义2个结构体 */
static const Data_t xStructsToSend[ 2 ] =
{
	{ eMotorSpeed,    10 }, /* CAN任务发送的数据 */
	{ eSpeedSetPoint, 5 }   /* HMI任务发送的数据 */
};


static void vSenderTask( void *pvParameters );
static void vReceiverTask( void *pvParameters );

/* 队列句柄, 创建队列时会设置这个变量 */
QueueHandle_t xQueue;

int main( void )
{
	prvSetupHardware();
	
    /* 创建队列: 长度为5,数据大小为4字节(存放一个整数) */
    xQueue = xQueueCreate( 5, sizeof( Data_t ) );

	if( xQueue != NULL )
	{
		xTaskCreate( vSenderTask, "CAN Task", 1000, ( void * ) &( xStructsToSend[ 0 ] ), 2, NULL );
		xTaskCreate( vSenderTask, "HMI Task", 1000, ( void * ) &( xStructsToSend[ 1 ] ), 2, NULL );

		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );

		vTaskStartScheduler();
	}
	else
	{
		/* 无法创建队列 */
	}

	return 0;
}

发送函数:

static void vSenderTask( void *pvParameters )
{
	BaseType_t xStatus;
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );

	/* 无限循环 */
	for( ;; )
	{
		/* 写队列
		xStatus = xQueueSendToBack( xQueue, pvParameters, xTicksToWait );

		if( xStatus != pdPASS )
		{
			printf( "Could not send to the queue.\r\n" );
		}
	}
}

接收函数:

static void vReceiverTask( void *pvParameters )
{
	/* 读取队列时, 用这个变量来存放数据 */
	Data_t xReceivedStructure;
	BaseType_t xStatus;

	/* 无限循环 */
	for( ;; )
	{
		xStatus = xQueueReceive( xQueue, &xReceivedStructure, 0 );

		if( xStatus == pdPASS )
		{
			/* 读到了数据 */
			if( xReceivedStructure.eDataID == eMotorSpeed )
			{
				printf( "From CAN, MotorSpeed = %d\r\n", xReceivedStructure.lDataValue );
			}
			else if( xReceivedStructure.eDataID == eSpeedSetPoint )
			{
				printf( "From HMI, SpeedSetPoint = %d\r\n", xReceivedStructure.lDataValue );
			}
		}
		else
		{
			/* 没读到数据 */
			printf( "Could not receive from the queue.\r\n" );
		}
	}
}

3.运行结果以及分析

在这里插入图片描述

  1. HMI 是最后创建的最高优先级任务,它先执行,一下子向队列写入 5
    个数据,把队列都写满了。
  2. 队列已经满了, HMI 任务再发起第 6 次写操作时,进入阻塞状态。这
    时 CAN 任务是最高优先级的就绪态任务,它开始执行。
  3. CAN 任务发现队列已经满了,进入阻塞状态;接收任务变为最高优先
    级的就绪态任务,它开始运行。
  4. 现在, HMI 任务、 CAN 任务的优先级都比接收任务高,它们都在等待
    队列有空闲的空间;一旦接收任务读出 1 个数据,会马上被抢占。被谁抢占?谁等待最久? HMI 任务!所以在 t4 时刻,切换到 HMI 任务。
  5. HMI 任务向队列写入第 6 个数据,然后再次阻塞,这是 CAN 任务已经
    阻塞很久了。接收任务变为最高优先级的就绪态任务,开始执行。
  6. 现在, HMI 任务、 CAN 任务的优先级都比接收任务高,它们都在等待
    队列有空闲的空间;一旦接收任务读出 1 个数据,会马上被抢占。被谁抢占?谁等待最久? CAN 任务!所以在 t6 时刻,切换到 CAN 任务。
  7. CAN 任务向队列写入数据,因为仅仅有一个空间供写入,所以它马上
    再次进入阻塞状态。这时 HMI 任务、 CAN 任务都在等待空闲空间,只有接收任
    务可以继续执行。
    在这里插入图片描述

总结

谁等的最久,谁先执行。
跟着韦东山老师学习的。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值