【复习笔记】FreeRTOS(六) 队列操作

本文是FreeRTOS复习笔记的第六节,队列操作。

上一篇文章: 【复习笔记】FreeRTOS(五)时间片调度


1.队列操作

队列是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息,队列中可以存储有限的、大小固定的数据项目。任务与任务、任务与中断之间要交流的数据保存在队列中,叫做队列项目。队列所能保存的最大数据项目数量叫做队列的长度,创建队列的时候会指定数据项目的大小和队列的长度。由于队列用来传递消息的,所以也称为消息队列。

1.1.队列操作过程

创建队列
在这里插入图片描述
上图中任务 A 要向任务 B 发送消息,这个消息是x 变量的值。首先创建一个队列,并且指定队列的长度和每条消息的长度。这里我们创建了一个长度为 4 的队列,因为要传递的是x值,而x是个 int类型的变量,所以每条消息的长度就是 int 类型的长度,在 STM32 中就是4字节,即每条消息是 4 个字节的。
向队列发送第一个消息
在这里插入图片描述
上图中任务A的变量x值为10,将这个值发送到消息队列中。此时队列剩余长度就是3了。队列中发送消息是采用拷贝的方式,所以一旦消息发送完成变量x就可以再次被使用,赋其他的值。
向队列发送第二个消息
在这里插入图片描述
上图中任务 A 又向队列发送了一个消息,即新的x 的值,这里是 20。此时队列剩余长度为 2。
从队列中读取消息
在这里插入图片描述
上图中任务 B 从队列中读取消息,并将读取到的消息值赋值给 y,这样 y 就等于 10了。任务 B 从队列中读取消息完成以后可以选择清除掉这个消息或者不清除。当选择清除这个消息的话其他任务或中断就不能获取这个消息了,而且队列剩余大小就会加一,变成 3。如果不清除的话其他任务或中断也可以获取这个消息,而队列剩余大小依旧是 2。

队列的内容除了队列的创建、队列的出队、入队函数、队列的环形缓冲区的实现,还有数据的拷贝、先进先出、以及后进先出的实现、队列锁、以及队列任务级函数与中断级函数的区别等知识。

由于队列的知识也比较多,这里只是进行一个简单的使用,学会队列的基本操作。

1.2.队列操作常用的API函数

函数名称作用
xQueueCreate()动态创建队列
xQueueCreateStatic()静态创建队列
xQueueSend()队列数据发送
xQueueReceive()队列数据接收

二、实验设计

实验目的:学会对FreeRTOS 简单队列操作
实验设计:设计两个任务: task1 task 和 task2 task ,其中 task1 task 和 task2 task的任务优先级相同,这两个任务的任务功能如下:

  • task1 task :发送一串字符
  • task2 task :接收任务1的字符

三、测试例程

主函数 main.c代码如下:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"


/*使用结构体储存数据*/
struct QueuePrint
{
	uint8_t Tick;
	char Data[20];
};

QueueHandle_t myPrintfQueue;

void task1_task(void *p); //任务函数
void task2_task(void *p); //任务函数


int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
	delay_init(168);		//初始化延时函数
	uart_init(115200);     	//初始化串口
	LED_Init();		        //初始化LED端口

	/*动态创建队列,2个队列项目,一个发送一个接收,以及消息长度(结构体大小)*/
	myPrintfQueue=xQueueCreate(2,sizeof(struct QueuePrint));
	if(myPrintfQueue==NULL)
	{
		printf("队列创建失败!\r\n");
	}
    xTaskCreate(task1_task,"task1_task",128,NULL,2,NULL); //任务1        
    xTaskCreate(task2_task,"task2_task",128,NULL,2,NULL);  //任务2 	
	
    vTaskStartScheduler();          //开启任务调度
}
 

//任务1函数 发送数据
void task1_task(void *p)
{
	struct QueuePrint SendData={
		.Data="adafsf" //随便发个字符串
	};

	while(1)
	{
		SendData.Tick++;
		xQueueSend(myPrintfQueue,&SendData,0); //队列句柄,发送内容的地址,阻塞时间
		printf("task1发送数据:%s 次数%d\r\n",SendData.Data,SendData.Tick);
		vTaskDelay(500);
	}
}   


//任务2函数接收数据 
void task2_task(void *p)
{

	struct QueuePrint ReceData;
	BaseType_t xStatus;
	while(1)
	{
		xStatus=xQueueReceive(myPrintfQueue,&ReceData,portMAX_DELAY);//portMAX_DELAY:读不到数据就会一直停留在此
		if(xStatus==pdPASS) //判断接收到数据
		{
			taskENTER_CRITICAL();           //进入临界区
		     printf("task2收到数据:%s 次数%d\r\n",ReceData.Data,ReceData.Tick);
			taskEXIT_CRITICAL();            //退出临界区
		}
	}
}

四、实验效果

实验效果如下:
在这里插入图片描述

接上串口,可以看到每500ms,串口打印任务1发送的内容和任务运行次数,以及任务2接收到的内容和任务执行次数,而且收发的数据保持一致。

本节主要是学习和掌握队列操作,以及相关API函数的基本使用。其实在FreeRTOS中队列的重要性也不言而喻,与FreeRTOS任务调度同等重要,因为后面的各种信号量基本都是基于队列的。
完整程序放在gitee仓库上:程序下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值