欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

FreeRTOS 消息队列总结

程序员文章站 2024-03-22 09:23:28
...

一、消息队列的应用场景

        消息队列可以应用于发送不定长消息的场合;队列是FreeRTOS 主要的任务间通讯方式,可以在任务与任务间、中断和任务间传送信息;

二、消息队列相关的函数

1、xQueueCreate()       //动态创建消息队列函数

2、xQueueCreateStatic()         //静态创建消息队列函数

3、vQueueDelete()        //消息队列删除函数

4、xQueueSend()        //向队列尾部发送一个队列消息

5、xQueueSendToBack()        //向队列尾部发送一个队列消息  等同于4

6、xQueueSendToFront()        //向队列头部发送一个消息

7、xQueueSendFromISR()        //向队列头部发送一个消息  用在中断中

8、xQueueSendToBackFromISR()              //向队列头部发送一个消息  用在中断中 等同于7

9、xQueueGenericSend()           //发送消息函数的原型

 

10、xQueueReceive()        //从一个队列中接收消息并把消息从队列中删除 决不能再中断中使用

11、xQueuePeek()           //从一个队列中接收消息 把消息从队列中删除

12、xQueueReceiveFromISR ()      //从一个队列中接收消息并把消息从队列中删除 用在中断中

13、xQueuePeekFromISR()        //从一个队列中接收消息 把消息从队列中删除 用在中断中

14、xQueueGenericReceive()        //接收消息函数的原型

三、注意事项

1、必须在FreeRTOSConfig.h 把 configSUPPORT_DYNAMIC_ALLOCATION 定义为 1。

2、队列是内核对象,具有自己独立权限;

3、如果消息过于庞大,可以将消息的地址作为消息进行发送、接收。

4、获取队列消息时,要定义一个大于或等于消息的大小。

5、队列读取采用的是先进先出(FIFO)模式,也支持后进先出(LIFO)模式

四、实验数据

//FreeRTOS 库 
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

//硬件库
#include "stm32f10x.h"
#include "bsp_usart.h"

//C库
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/******************** 说  明 ************************
任务优先级:   数值越大 优先级高
****************************************************/
//堆栈大小
#define AppTaskCreate_Size 512 //创建任务的堆栈大小
#define ReceiveTask_Size   512 //  堆栈大小
#define SendTask_Size      512

//任务优先级 priority
#define AppTaskCreate_priority 1
#define ReceiveTask_priority   2
#define SendTask_priority      3

//申请任务句柄
static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t Receive_Task_Handle = NULL;
static TaskHandle_t SendTask_Handle = NULL;

//内核对象句柄
QueueHandle_t Test_Queue =NULL;

#define QUEUE_LEN  4 //队列的长度
#define QUEUE_SIZE 1 //队列中每个消息的大小

//全局变量 串口部分
extern u8 USART1_BUFF[64];
extern u16 USART1_ReceiveLength;
extern u8 USART1_ReceiveEndFlag;

//任务声明
static void AppTaskCreate(void); //用于创建任务
static void Receive_Task(void* pvParameters);//LED 任务的实现
static void Send_Task(void* pvParameters);

static void BSP_Init(void);//用于初始化板载相关资源

/******************主函数***********************/
int main(void)
{	
	BaseType_t xReturn = pdPASS;
	
	BSP_Init();
	
	printf(" usart send 1 or 2. task send queue data \r\n");
	printf(" Receive task receive data in usart displey \r\n");
	xReturn =xTaskCreate(
		(TaskFunction_t ) AppTaskCreate,          //任务函数入口
		(const char*    ) "AppTaskCreate",        //任务名字
		(uint16_t       ) AppTaskCreate_Size,	  //任务栈大小
		(void*          ) NULL,                   //任务入口函数参数
		(UBaseType_t    ) AppTaskCreate_priority, //任务优先级
		(TaskHandle_t*  ) &AppTaskCreate_Handle); //任务控制块指针
	//启动任务调度
	if(pdPASS == xReturn)
		vTaskStartScheduler();//启动任务调度
	else
		return -1;
	while(1);//正常 不会执行到这里
}
//创建任务
static void AppTaskCreate(void)
{
	BaseType_t xReturn = pdPASS;
	
	taskENTER_CRITICAL();//进入临界区
	//创建 消息队列 Test_Queue
	Test_Queue =xQueueCreate((UBaseType_t )QUEUE_LEN,(UBaseType_t )QUEUE_SIZE);
	if(NULL != Test_Queue)
		printf("Create Test_Queue data queue ok!\r\n");
	
	xReturn = xTaskCreate(
		(TaskFunction_t ) Receive_Task,    //任务函数
		(const char*)    "Receive_Task",   //任务名称
		(uint32_t )      ReceiveTask_Size, //任务堆栈大小
		(void* )         NULL,             //传递给任务函数的参数
		(UBaseType_t )   ReceiveTask_priority,   //任务优先级
		(TaskHandle_t*) &Receive_Task_Handle);   //任务控制块
	if(pdPASS == xReturn )
		printf("Receive_Task 创建任务成功\r\n");
	
	xReturn = xTaskCreate(
		(TaskFunction_t ) Send_Task,    //任务函数
		(const char*)    "Send_Task",   //任务名称
		(uint32_t )      SendTask_Size, //任务堆栈大小
		(void* )         NULL,          //传递给任务函数的参数
		(UBaseType_t )   SendTask_priority, //任务优先级
		(TaskHandle_t*) &SendTask_Handle);  //任务控制块
	if(pdPASS == xReturn )
		printf("Send_Task 创建任务成功\r\n");
	
	vTaskDelete(AppTaskCreate_Handle);
	
	taskEXIT_CRITICAL();
}

//接收打印任务
static void Receive_Task(void* parameter)
{
	BaseType_t xReturn = pdTRUE;//定义一个创建信息返回值,默认为pdTRUE
	u8 r_queue;//定义一个接收消息的变量
	
	while(1)
	{
		xReturn = xQueueReceive(Test_Queue,    //消息队列的句柄
					&r_queue,      //发送的消息内容
					portMAX_DELAY);//等待时间 一直等
		if(pdTRUE == xReturn)
			printf("Receive data is %d\r\n\r\n",r_queue);
		else
			printf("Data receive error:0x%1x \r\n",xReturn);
	}
}
//发送任务
static void Send_Task(void* pvParameters)
{
	BaseType_t xReturn = pdPASS;//定义一个创建信息返回值
	u8 sendData1 = 1;
	u8 sendData2 = 2;
	while(1)
	{
		if(USART1_ReceiveEndFlag == USART1ReceiveOk)
		{
			if(strstr((const char *)USART1_BUFF,"1") != NULL)
			{
				printf("send data is sendData1\r\n");
				xReturn = xQueueSend(Test_Queue,&sendData1,0);
				if(pdPASS == xReturn)
					printf("send sendData1 data OK!\r\n\r\n");
			}
			else if(strstr((const char *)USART1_BUFF,"2") != NULL)
			{
				printf("send data is sendData2\r\n");
				xReturn = xQueueSend(Test_Queue,&sendData2,0);
				if(pdPASS == xReturn)
					printf("send sendData2 data OK!\r\n\r\n ");
			}
			else
			{
				printf("Please enter 1 or 2! \r\n");
			}
			USART1_ReceiveEndFlag=0; //清标志位
			USART1_ReceiveLength =0; //清长度
			memset(USART1_BUFF, 0, sizeof(USART1_BUFF));//清缓存
		}
		vTaskDelay(20);// 延时 20 个 tick 
	}
}
//硬件初始化函数
static void BSP_Init(void)
{
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
	USART_Config();
}	

// 串口中断服务函数
u8 USART1_BUFF[64];
u16 USART1_ReceiveLength;
u8 USART1_ReceiveEndFlag=0;
void DEBUG_USART_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(DEBUG_USARTx);
		USART1_BUFF[USART1_ReceiveLength]=ucTemp;
		if(USART1_BUFF[USART1_ReceiveLength]== 0x0a)//\n
		{
			if(USART1_BUFF[USART1_ReceiveLength-1] == 0x0d)//\r
			{
				USART1_ReceiveEndFlag=USART1ReceiveOk;//接收完成
			}	
		}
		else
		{
			++USART1_ReceiveLength;
		}
		//USART_SendData(DEBUG_USARTx,ucTemp);    
	}	 
}