FreeRTOS-队列

一、队列简介

  • 队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递)
  • 使用队列的情况下如图,在读队列时,会进入临界区,无法触发任务调度,不会出现多任务冲突,只需要调用API函数即可
    在这里插入图片描述
  • 在队列中可以存储数量有限大小固定的数据。队列中的每一个数据叫做“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度
  • 队列采用先进先出(FIFO)的数据存储缓冲机制,即先入队的数据会先从队列中被读取,FreeRTOS也可以配置成先进后出的方式
  • FreeRTOS中队列采用实际值传递,或传递地址
  • 任何任务和中断都可以向队列发送/读取消息
  • 当任务向一个队列发送消息时,可以指定一个阻塞时间,设置阻塞时间,确定是否等待或者返回
  • 当任务A写入队列时,队列已满的情况下,可以将该任务挂在阻塞列表等待发送列表。当任务B从队列读取数据时,队列无数据的情况下,将任务挂在阻塞列表等待接收列表里

二、队列相关函数

2.1 队列结构体

  • 下面是队列结构体介绍
typedef struct QueueDefinition
{
    int8_t * pcHead;//存储区域的起始地址
    int8_t * pcWriteTo;//下一个写入位置
    union
    {
        QueuePointers_t xQueue;//用于队列使用时
        SemaphoreData_t xSemaphore;//用于互斥信号量和递归互斥信号量时
    } 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;

2.2 队列相关API函数

  • 使用队列时,主要流程为:创建队列 -> 写队列 -> 读队列
  • 创建队列相关API函数
xQueueCreate();//动态方式创建队列
xQueueCreateStatic();//静态方式创建队列
  • 动态创建队列函数宏定义
#define xQueueCreate(uxQueueLength,uxItemSize)
					xQueueGenericCreate( (uxQueueLength),(uxItemSize),(queueQUEUE_TYPE_BASE) )
//形参:队列长度  队列项目大小  代表创建的是队列还是互斥信号量等等
//返回值:NULL创建失败 队列创建成功返回队列句柄
  • 队列写入消息API函数
xQueueSend();//队列尾部写消息
xQueueSendToBack();//同上
xQueueSendToFront();//队列头部写消息
xQueueOverwrite();//覆写队列消息(只用于队列长度为1的情况)
xQueueSendFromISR();//在中断中往队列尾部写消息
xQueueSendToBackFromISR();//同上
xQueueSendToFrontFromISR();//在中断中往队列头部写消息
xQueueOverwriteFromISR();//在中断中覆写队列消息(只用于队列长度为1的情况)
  • 队列写入消息函数宏定义
#define 函数名	xQueueGenericSend((xQueue),(pvItemToQueue),(xTicksToWait),位置)
//形参:待写入的队列 待写入消息 阻塞超时时间 写入位置
//返回值:pdTRUE队列写入成功 errQUEUE_FULL队列写入失败
  • 队列写入一共有三种位置
#define queueSEND_TO_BACK		((BaseType_t)0)//尾部
#define queueSEND_TO_FRONT		((BaseType_t)1)//头部
#define queueOVERWRITE			((BaseType_t)2)//覆写(队列长度为1)
  • 队列读取消息API函数
xQueueReceive();//从队列头部读取消息,并删除消息
xQueuePeek();//从队列头部读取消息
xQueueReceiveFromISR();//在中断中从队列头部读取消息,并删除消息
xQueuePeekFromISR();//在中断中从队列头部读取消息

BaseType_t xQueueReceive(QueueHandle_t xQueue,void *const pvBuffer,TickType_t xTicksToWait)
//形参:待读取队列 信息读取缓冲区 阻塞超时时间
//返回值:pdTRUE 读取成功 pdFALSE 读取失败
BaseType_t xQueuePeek(QueueHandle_t xQueue,void *const pvBuffer,TickType_t xTicksToWait)
//形参:待读取队列 信息读取缓冲区 阻塞超时时间
//返回值:pdTRUE 读取成功 pdFALSE 读取失败

三、队列操作实验

  • 创建四个任务
  • start_task:创建task1、task2和task3
  • task1:当按键key0或key1按下,将按键键码拷贝到队列key_queue(入队),当key2按下,将传输大数据,拷贝大数据内容到队列big_data_queue
  • task2:读取队列key_queue中的消息(出队),打印出接收的键值
  • task3:从队列big_data_queue读取大数据地址,通过地址访问大数据
#define configSUPPORT_DYNAMIC_ALLOCATION					1//动态创建任务宏定义配置
#define INCLUDE_vTaskSuspend								1//挂起/恢复任务宏定义配置

//start_task参数宏定义
#define	START_TASK_STACK_SIZE 								128//堆栈大小
#define	START_TASK_PRIO										1//任务优先级
TaskHandle_t	start_task_handle;							//任务句柄
//task1参数宏定义
#define	TASK1_STACK_SIZE 									128//堆栈大小
#define	TASK1_PRIO											2//任务优先级
TaskHandle_t	task1_handle;								//任务句柄
//task2参数宏定义
#define	TASK2_STACK_SIZE 									128//堆栈大小
#define	TASK2_PRIO											3//任务优先级
TaskHandle_t	task2_handle;								//任务句柄
//task3参数宏定义
#define	TASK3_STACK_SIZE 									128//堆栈大小
#define	TASK3_PRIO											4//任务优先级
TaskHandle_t	task3_handle;								//任务句柄

QueueHandle_t key_queue;//小数据句柄
QueueHandle_t big_key_queue;//大数据句柄
char buff[] = "hello world";//大数据内容

//task1任务函数:入队操作
void task1( void * pvParameters )
{
		uint8_t KeyNum = 0;
		char *buf;
		buf = buff;//buf指针指向buff首地址
		BaseType_t err = 0;//返回值
		while(1)
		{
			KeyNum = Key_GetNum();
			if(KeyNum==0 || KeyNum==1)//键值写入队列
			{
				err = xQueueSend(key_queue,&KeyNum,portMAX_DELAY);//写入键值到队列中,返回值判断是否写入成功
			}
			else if(KeyNum == 2)//数组内容写入队列
			{
				err = xQueueSend(big_date_queue,&buf,portMAX_DELAY);//写入buf数组内容到队列中,返回值判断是否写入成功
			}
			vTaskDelay(10);//自带延时函数
		}
}
//task2任务函数:读取小数据(出队)
void task2( void * pvParameters )
{
		uint8_t KeyNum = 0;
		BaseType_t err = 0;
		while(1)
		{
			err = xQueueReceive(key_queue,&keyNum,portMAX_DELAY);//出队操作,返回值判断是否读取成功
		}
}
//task3任务函数:读取大数据(出队)
void task3( void * pvParameters )
{
		char *buf;
		BaseType_t err = 0;
		while(1)
		{
			err = xQueueReceive(big_date_queue,&buf,portMAX_DELAY);//出队操作,返回值判断是否读取成功
		}
}
//Start_task任务函数
void Start_task( void * pvParameters )
{
		taskENTER_CRITICAL();//进入临界区
		//创建任务1
		xTaskCreate(task1,//任务函数
					"task1",//任务名称
					TASK1_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					TASK1_PRIO,//优先级
					&task1_handle//任务句柄
					);
		//创建任务2
		xTaskCreate(task2,//任务函数
					"task2",//任务名称
					TASK2_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					TASK2_PRIO,//优先级
					&task2_handle//句柄
					);
		//创建任务3
		xTaskCreate(task3,//任务函数
					"task3",//任务名称
					TASK3_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					TASK3_PRIO,//优先级
					&task3_handle//句柄
					);
		vTaskDelete(start_task_handle);
		//删除自身任务Start_task,start_task_handle或NULL都可以
		taskEXIT_CRITICAL();//退出临界区
}

//FreeRTOS入口函数,程序从此处开始执行
void freertos_demo()
{
		key_queue = xQueueCreate(2,sizeof(uint8_t));//创建小数据队列,2个队列项,按键返回字节,队列创建成功返回句柄,失败返回NULL
		big_date_queue = xQueueCreate(1,sizeof(char*));//创建大数据队列,1个队列项,字符数组首地址,队列创建成功返回句柄,失败返回NULL
		xTaskCreate(Start_task,//任务函数
					"Start_task",//任务名称
					START_TASK_STACK_SIZE,//堆栈大小/字
					NULL,//入口参数没有
					START_TASK_PRIO,//优先级
					&start_task_handle//句柄
					);//创建Start任务
		vTaskStartScheduler();//开启任务调度器,开启执行Start任务,创建task123
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值