5.物联网操作系统消息队列

一。消息队列的概念及应用

消息队列定义

FreeRTOS消息队列介绍

FreeRTOS消息队列工作原理

1.消息队列的作用

消息队列(queue),可以在任务与任务间、中断和任务间传递消息 实现任务接收来自其他任务或中断的不固定长度的消息

 2.FreeRTOS消息队列介绍

中断或者任务给任务发消息

 3.FreeRTOS消息队列工作原理

 二。实验:消息队列函数应用《在CPU的利用率的基础上创建》

功能需求

API

1.功能需求

 2.API

(1)xQueueCreate()

(2)xQueueSend()

 (3)xQueueSendFromISR()

(4) xQueueReceive()

(5) xQueueReceiveFromISR()

 3.STM32CubeMX功能配置

 (1)led端口配置

(2)Usart1中断配置(中断使能)

 (3)创建消息队列

注意:上面那个图应该是8字节,因为一个字符就是8字节

补充:原理解释:

 由上述原理图得(第一个图),USART中断接受到的数据的控制为为RXNE。

HAL库指南图得(第二个图),HAL库中有专门使能串口中断的函数。

4.消息队列接收和发送功能开发

 步骤:

(1)串口中断使能

	//¿ªÆôÖÐ¶Ï ÖжÏԴΪ½ÓÊռĴæÆ÷²»Îª¿Õ
  __HAL_UART_ENABLE_IT(uartHandle,UART_IT_RXNE);

(2)中断服务入队操作

 在上面导入数据

extern osMessageQId CmdQueueHandle;
	uint8_t u8Data;
	//ÅжϽÓÊÕ±êÖ¾ÖÃλ
	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) == SET){
		//¶ÁÈ¡½ÓÊռĴæÆ÷
		u8Data = huart1.Instance->DR;
		//½øÐÐÈë¶Ó²Ù×÷
		xQueueSendFromISR(CmdQueueHandle,&u8Data,NULL);
	}

(3)出队操作

《1》电脑上输入字符串,串口上显示同样的字符串

uint8_t u8CmdBuff[20];//全局变量
	  //每次读取信息之前,首先初始化为0
	  u8Index = 0;
	  //一直等待接受消息,第一个消息应该放在消息缓存区的第一个元素上
	  if(xQueueReceive(CmdQueueHandle,&u8CmdBuff[u8Index++],portMAX_DELAY)==pdPASS){
		  while(xQueueReceive(CmdQueueHandle,&u8CmdBuff[u8Index++],50)){}
			u8CmdBuff[u8Index]='\0';//保证完整的字符串
			  printf("%s\r\n",u8CmdBuff);
	  }

结果:

 (3)字符串命令操作灯的亮灭

《1》使用字符串数组储存命令

#define LED_NUM  4

uint8_t *OpenString[LED_NUM] = {
"openled6",
"openled7",
"openled8",
"openled9",
};

uint8_t *CloseString[LED_NUM] = {
"closeled6",
"closeled7",
"closeled8",
"closeled9",
};

GPIO_TypeDef * LedPort[LED_NUM] = {
Led6_GPIO_Port,
Led7_GPIO_Port,
Led8_GPIO_Port,
Led9_GPIO_Port
};

uint16_t LedPin[LED_NUM] ={
Led6_Pin,
Led7_Pin,
Led8_Pin,
Led9_Pin
};

《2》写一个函数,目标是比较字符串命令与输入数据的比较,比较通过执行指定的命令。

void vParseString(uint8_t *buff){
	//与open灯命令比较
    uint8_t i;
    for(i=0;i<LED_NUM;i++){
      if(strcmp((char const*)buff,(char const*)OpenString[i]) == 0){
        HAL_GPIO_WritePin(LedPort[i], LedPin[i], GPIO_PIN_RESET);
        printf("Cmd is %s\n",OpenString[i]);
		  return;    
      }  
    }
	//与close灯命令比较
    for(i=0;i<LED_NUM;i++){
      if(strcmp((char const*)buff,(char const*)CloseString[i]) == 0){
      HAL_GPIO_WritePin(LedPort[i], LedPin[i], GPIO_PIN_SET);
      printf("Cmd is %s\n",CloseString[i]);
		  return;    
      }  
    }
}

《3》在任务主函数下调用函数,注意:每回合结束要把缓存区(自己设置的字符串)清零

	//比较命令	
	vParseString(u8CmdBuff);
	//清空字符串		
	memset(u8CmdBuff,0,20);

结果:输入openled6,打开led6灯;输入closeled6,关闭led6灯。


三。消息队列实现原理

1.消息队列控制块

2.消息队列创建

3.消息队列删除

4.消息队列在任务中发送

5.消息队列在中断中发送 

6.消息队列在任务中接收

7.消息队列在中断中接收

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要在STM32F407VET6上搭载FreeRTOS操作系统,并且实现串口通信功能。接下来,我们可以通过消息队列来实现控制板载LED的开关。 在主函数中,我们创建一个消息队列,然后创建一个任务来接收串口命令并将命令发送到消息队列中。另外,我们还需要创建一个任务来读取消息队列中的数据,并根据命令来控制LED的开关。 下面是一个简单的示例代码: ```c #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "stm32f4xx.h" #include "stm32f4xx_hal.h" #define LED_PIN GPIO_PIN_13 #define LED_PORT GPIOC TaskHandle_t xTask1Handle; TaskHandle_t xTask2Handle; QueueHandle_t xQueue; void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitStruct.Pin = LED_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct); } void USART1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; USART_InitTypeDef USART_InitStruct = {0}; NVIC_InitTypeDef NVIC_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_USART1_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); USART_InitStruct.BaudRate = 115200; USART_InitStruct.WordLength = USART_WORDLENGTH_8B; USART_InitStruct.StopBits = USART_STOPBITS_1; USART_InitStruct.Parity = USART_PARITY_NONE; USART_InitStruct.Mode = USART_MODE_TX_RX; USART_InitStruct.CLKPolarity = USART_POLARITY_LOW; USART_InitStruct.CLKPhase = USART_PHASE_1EDGE; USART_InitStruct.CLKLastBit = USART_LASTBIT_DISABLE; HAL_USART_Init(&USART_InitStruct); NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; HAL_NVIC_Init(&NVIC_InitStruct); HAL_NVIC_EnableIRQ(USART1_IRQn); } void USART1_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; char cReceivedChar = 0; if (__HAL_USART_GET_FLAG(&huart1, USART_FLAG_RXNE) != RESET) { __HAL_USART_CLEAR_FLAG(&huart1, USART_FLAG_RXNE); cReceivedChar = (char)(huart1.Instance->DR & 0xFF); xQueueSendFromISR(xQueue, &cReceivedChar, &xHigherPriorityTaskWoken); } portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void vTask1(void *pvParameters) { char cCommand = 0; while (1) { if (HAL_USART_Receive(&huart1, (uint8_t *)&cCommand, 1, 1000) == HAL_OK) { xQueueSend(xQueue, &cCommand, 0); } } } void vTask2(void *pvParameters) { char cReceivedChar = 0; while (1) { if (xQueueReceive(xQueue, &cReceivedChar, portMAX_DELAY) == pdTRUE) { switch (cReceivedChar) { case 'o': HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); break; case 'c': HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); break; default: break; } } } } int main(void) { HAL_Init(); LED_Init(); USART1_Init(); xQueue = xQueueCreate(10, sizeof(char)); xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &xTask1Handle); xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &xTask2Handle); vTaskStartScheduler(); while (1) { } } ``` 在该示例中,我们使用消息队列来实现串口命令的传递和控制LED的开关。当接收到字符'o'时,我们将板载LED打开,当接收到字符'c'时,我们将板载LED关闭。通过这种方式,我们可以通过串口来控制板载LED的开关。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值