【FreeRTOS 消息队列】消息队列传递变量

本文详细介绍了如何在STM32CubeMX环境中创建和管理消息队列,包括xQueue1和xQueue2的实例,以及在任务间使用消息队列进行数据交换和通信的示例。通过K1、K2和K3按键操作展示发送与接收过程,并结合FreeRTOS和硬件中断的使用,展示了高效的任务协调和实时通信技术。
摘要由CSDN通过智能技术生成

消息队列创建及运行,参阅安富莱电子demo

static QueueHandle_t xQueue1 = NULL;
static QueueHandle_t xQueue2 = NULL;


typedef struct Msg
{
	uint8_t  ucMessageID;
	uint16_t usData[2];
	uint32_t ulData[2];
}MSG_T;

MSG_T   g_tMsg; /* 定义一个结构体用于消息队列 */



static void vTaskTaskUserIF(void *pvParameters)
{
	MSG_T   *ptMsg;
	uint8_t ucCount = 0;
	uint8_t ucKeyCode;
	uint8_t pcWriteBuffer[500];
	
	/* 初始化结构体指针 */
	ptMsg = &g_tMsg;
	
	/* 初始化数组 */
	ptMsg->ucMessageID = 0;
	ptMsg->ulData[0] = 0;
	ptMsg->usData[0] = 0;

    while(1)
    {
		ucKeyCode = bsp_GetKey();
		
		if (ucKeyCode != KEY_NONE)
		{
			switch (ucKeyCode)
			{
				/* K1键按下 打印任务执行情况 */
				case KEY_DOWN_K1:			 
					printf("=================================================\r\n");
					printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");
					vTaskList((char *)&pcWriteBuffer);
					printf("%s\r\n", pcWriteBuffer);
				
					printf("\r\n任务名       运行计数         使用率\r\n");
					vTaskGetRunTimeStats((char *)&pcWriteBuffer);
					printf("%s\r\n", pcWriteBuffer);
					break;
				
				/* K2键按下,向xQueue1发送数据 */
				case KEY_DOWN_K2:
					ucCount++;
				
					/* 向消息队列发数据,如果消息队列满了,等待10个时钟节拍 */
					if( xQueueSend(xQueue1,
								   (void *) &ucCount,
								   (TickType_t)10) != pdPASS )
					{
						/* 发送失败,即使等待了10个时钟节拍 */
						printf("K2键按下,向xQueue1发送数据失败,即使等待了10个时钟节拍\r\n");
					}
					else
					{
						/* 发送成功 */
						printf("K2键按下,向xQueue1发送数据成功\r\n");						
					}
					break;
				
				/* K3键按下,向xQueue2发送数据 */
				case KEY_DOWN_K3:
					ptMsg->ucMessageID++;
					ptMsg->ulData[0]++;;
					ptMsg->usData[0]++;
					
					/* 使用消息队列实现指针变量的传递 */
					if(xQueueSend(xQueue2,                  /* 消息队列句柄 */
								 (void *) &ptMsg,           /* 发送结构体指针变量ptMsg的地址 */
								 (TickType_t)10) != pdPASS )
					{
						/* 发送失败,即使等待了10个时钟节拍 */
						printf("K3键按下,向xQueue2发送数据失败,即使等待了10个时钟节拍\r\n");
					}
					else
					{
						/* 发送成功 */
						printf("K3键按下,向xQueue2发送数据成功\r\n");						
					}
				
				/* 其他的键值不处理 */
				default:                     
					break;
			}
		}
		
		vTaskDelay(20);
	}
}

static void vTaskLED(void *pvParameters)
{
	MSG_T *ptMsg;
	BaseType_t xResult;
	const TickType_t xMaxBlockTime = pdMS_TO_TICKS(200); /* 设置最大等待时间为200ms */
	
    while(1)
    {
		xResult = xQueueReceive(xQueue2,                   /* 消息队列句柄 */
		                        (void *)&ptMsg,  		   /* 这里获取的是结构体的地址 */
		                        (TickType_t)xMaxBlockTime);/* 设置阻塞时间 */
		
		
		if(xResult == pdPASS)
		{
			/* 成功接收,并通过串口将数据打印出来 */
			printf("接收到消息队列数据ptMsg->ucMessageID = %d\r\n", ptMsg->ucMessageID);
			printf("接收到消息队列数据ptMsg->ulData[0] = %d\r\n", ptMsg->ulData[0]);
			printf("接收到消息队列数据ptMsg->usData[0] = %d\r\n", ptMsg->usData[0]);
		}
		else
		{
			/* 超时 */
		}
    }
}

static void vTaskMsgPro(void *pvParameters)
{
	BaseType_t xResult;
	const TickType_t xMaxBlockTime = pdMS_TO_TICKS(300); /* 设置最大等待时间为300ms */
	uint8_t ucQueueMsgValue;
	
    while(1)
    {
		xResult = xQueueReceive(xQueue1,                   /* 消息队列句柄 */
		                        (void *)&ucQueueMsgValue,  /* 存储接收到的数据到变量ucQueueMsgValue中 */
		                        (TickType_t)xMaxBlockTime);/* 设置阻塞时间 */
		
		if(xResult == pdPASS)
		{
			/* 成功接收,并通过串口将数据打印出来 */
			printf("接收到消息队列数据ucQueueMsgValue = %d\r\n", ucQueueMsgValue);
		}
		else
		{
			/* 超时 */
		}
    }
}

int main(void)
{
	/* 
	  在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
	  这样做的好处是:
	  1. 防止执行的中断服务程序中有FreeRTOS的API函数。
	  2. 保证系统正常启动,不受别的中断影响。
	  3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
	  在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
	  和cpsie i是等效的。
     */
	__set_PRIMASK(1);  
	
	/* 创建任务 ,具体创建任务参阅上一篇【FreeRTOS 任务】任务创建及运行 */
	AppTaskCreate();

	/* 创建任务通信机制 */
		/* 创建10个uint8_t型消息队列 */
	xQueue1 = xQueueCreate(10, sizeof(uint8_t));
    if( xQueue1 == 0 )
    {
        /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
    }
	/* 创建10个存储指针变量的消息队列,由于CM3/CM4内核是32位机,一个指针变量占用4个字节 */
	xQueue2 = xQueueCreate(10, sizeof(struct Msg *));
    if( xQueue2 == 0 )
    {
        /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
    }
	
    /* 启动调度,开始执行任务 */
    vTaskStartScheduler();

	/* 
	  如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
	  heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
	  #define configTOTAL_HEAP_SIZE	      ( ( size_t ) ( 17 * 1024 ) )
	*/
	while(1);
}


/* 如果程序使用到了硬件中断请使用以下方式 */
static void TIM1_IRQHandler(void)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	g_uiCount++;
	/* 向消息队列发数据 */
	xQueueSendFromISR(xQueue1,
					  (void *)&g_uiCount,
					  &xHigherPriorityTaskWoken);
	/* 如果 xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
	portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

static void TIM2_IRQHandler(void)
{
	MSG_T *ptMsg;
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	/* 初始化结构体指针 */
	ptMsg = &g_tMsg;
	/* 初始化数组 */
	ptMsg->ucMessageID++;
	ptMsg->ulData[0]++;
	ptMsg->usData[0]++;
	/* 向消息队列发数据 */
	xQueueSendFromISR(xQueue2,
					 (void *)&ptMsg,
					 &xHigherPriorityTaskWoken);
	/* 如果 xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
	portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

STM32CubeMX 队列创建及运行
以下是普通变量队列创建和运行

注意: STM32CubeMX 生成的代码消息队列目前只能传递普通变量,如果传递结构体或者其它类型变量,最好不使用 cmsis_os.h封装好的API


/* USER CODE BEGIN 4 */

void MessageQTask(void const * argument)
{
  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  osEvent EventMessage;
  for(;;)
  {
		EventMessage = osMessageGet (myMessageQueueIdHandle, 10);
		if(EventMessage.status == osEventMessage)
		{
			printf("MessageGet v : %d\r\n", EventMessage.value.v);
		}else{
			printf("MessageGet v null\r\n");
		}
		osDelay(1000);	
  }
  /* USER CODE END 5 */
}


void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN 5 */
  /* Infinite loop */
	int32_t count = 0;
	uint8_t bits  = 1;
  for(;;)
  {
		//HAL_UART_Transmit(&huart1,"StartDefaultTask\r\n",strlen("StartDefaultTask\r\n"),1000);	
		count++;
		if(count == 1)
		{
				count = 0;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
				bits = bits + 1;
				osMessagePut (myMessageQueueIdHandle, bits, 10);
		}
	  osDelay(10);	
	  osThreadSuspend(defaultTaskHandle);	//挂起任务
  }
  /* USER CODE END 5 */
}
int main(void)
{
  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
	
  /* 参数说明:队列结构体名称, 队列深度, 队列类型 */
  osMessageQDef(myMessageQueueName, 10, uint8_t);
  /* 参数说明:取定义好的队列结构体地址, 默认NULL */
  myMessageQueueIdHandle = osMessageCreate (osMessageQ(myMessageQueueName), NULL)
  /* USER CODE END RTOS_QUEUES */
  
  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
	
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
	
  osThreadDef(MessageQTask, MessageQTask, osPriorityHigh, 0, 128);
  SignalTaskHandle = osThreadCreate(osThread(MessageQTask), NULL);
  /* USER CODE END RTOS_THREADS */
  
  /* Start scheduler */
  osKernelStart();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值