FreeRTOS系列|消息队列二

本文主要介绍如何在任务或中断中向队列发送消息或者从队列中接收消息。

使用STM32CubeMX将FreeRTOS移植到工程中,创建两个任务以及两个消息队列,并开启两个中断

两个任务

  • Keyscan_Task:读取按键的键值,并将键值发送到队列Key_Queue中
  • Keyprocess_Task:按键处理任务,读取队列Key_Queue中的消息,并根据不同的消息值做相应的处理

两个队列

  • Msg_Queue:用于传递串口发送过来的消息
  • Key_Queue:用于传递按键值

两个中断

  • 串口接收中断:接收串口发来的数据,并将接收到的数据发送到队列Msg_Queue中
  • 定时器中断:定时读取队列Msg_Queue中的消息,并控制LED3/LED4的亮灭
1. STM32CubeMX设置
  • RCC设置外接HSE,时钟设置为72M
  • PC0/PC1/PC2/PC3设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • PA0设置为GPIO输入模式、下拉模式;PE2/PE3/PE4设置为GPIO输入模式、上拉模式
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位;开启串口中断
  • 激活TIM3定时器,时钟源选择为内部时钟,PSC预分频设置为7200-1,向上计数,自动重装载值(ARR)设置为5000-1,激活TIM3定时器中断;根据公式可算出:计数器时钟CK_CNT = 72M/7200 = 10000Hz,计时器中断时间为 ARR/10000 = 500ms。可参考定时器中断介绍
  • 激活FreeRTOS,添加任务,设置任务名称、优先级、堆栈大小、函数名称等参数

在这里插入图片描述
在这里插入图片描述

  • 添加队列Msg_Queue和Key_Queue,如下图设置

在这里插入图片描述

  • 使用FreeRTOS操作系统,一定要将HAL库的Timebase Source从SysTick改为其他定时器,选好定时器后,系统会自动配置TIM
  • 输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
2. MDK-ARM软件编程
  • 创建按键驱动文件key.c和key.h,参考按键输入例程
  • 添加KeyscanTask、KeyprocessTask任务函数代码
/******************KeyscanTask*******************/
//扫描按键键值,并将键值入队到Key_Queue队列中
void KeyscanTask(void const * argument){
  uint8_t key;
  BaseType_t err;
  
  for(;;){
	key = KEY_Scan(0);
	if((Key_QueueHandle!=0)&&(key)){
	  err = xQueueSend(Key_QueueHandle,&key,10);
	  if(err == errQUEUE_FULL)
		printf("Key_Queue is Full, data send failed!\r\n");
	  else
		printf("Send data to Key_Queue successed!\r\n");
	}
    osDelay(10);
  }
}
/******************KeyprocessTask*******************/
//按键处理函数,从Key_Queue队列中读出键值,控制LED1/LED2的亮灭
void KeyprocessTask(void const * argument){
  uint8_t key_value;

  for(;;){
    if(Key_QueueHandle != 0){
	  if(xQueueReceive(Key_QueueHandle,&key_value,portMAX_DELAY)){
		switch(key_value)
		{
		  case KEY_UP_PRES:
			HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
			printf("LED0 Togglen!\r\n");
			break;
		  case KEY_DOWN_PRES:
			HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_1);
			printf("LED1 Togglen!\r\n");
			break;
		}
	  }
	}
	osDelay(10);
  }
}

  • 添加串口中断回调函数:将串口输入的字符进行入队操作
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  RxBuff[Rx_Count++]=RxByte;	
  if(RxByte==0x0A){
	xQueueSendFromISR(Msg_QueueHandle,RxBuff,NULL);	//进行入队操作	
	printf("Send CMD to Msg_Queue FromISR succesed!\r\n");
	Rx_Count=0;
  }
  if(Rx_Count > 8){
	printf("Wrong CMD, Please Check...!\r\n");
	memset(RxBuff,0,sizeof(RxBuff));
	Rx_Count=0;
  }	
  while(HAL_UART_Receive_IT(&huart1,&RxByte,1)==HAL_OK);
}

  • 添加定时器中断回调函数:每500ms检查一下Msg_Queue是否有数据,如果有数据从Msg_Queue中出队,并对字符串进行比较从而控制LED3/LED4的亮灭
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  if(htim == &htim3){
	uint8_t RxCMD[8];
	if(Msg_QueueHandle != 0){	
	  if(xQueueReceiveFromISR(Msg_QueueHandle,RxCMD,NULL)){					
		printf("Read CMD Msg_Queue from ISR is:");
		for(int i =0;i<8;i++)
		  printf("%c",RxCMD[i]);
		printf("\n");
	  }
			
	if(strncmp((char *)RxCMD,"LED3on",6) == 0)
	  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_RESET);		
	else if(strncmp((char *)RxCMD,"LED3off",6) == 0)
	  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_SET);	
	else if(strncmp((char *)RxCMD,"LED4on",6) == 0)
	  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,GPIO_PIN_RESET);	
	else if(strncmp((char *)RxCMD,"LED4off",6) == 0)
	  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,GPIO_PIN_SET);	
    }
  }
}


  • 在main.c中添加开启串口接收中断和定时器中断代码
int main(void){
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM3_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  printf("Queue test....\r\n");
  if(HAL_OK == HAL_UART_Receive_IT(&huart1,&RxByte,1))
	printf("UART_Receive_IT successed!\r\n");
  else 
	printf("UART_Receive_IT failed!\r\n");
		
  if(HAL_OK == HAL_TIM_Base_Start_IT(&htim3))
	printf("TIM3_Base_Start_IT successed!\r\n");
  else 
	printf("TIM3_Base_Start_IT failed!\r\n");
  /* USER CODE END 2 */
  MX_FREERTOS_Init(); 
  osKernelStart();
  while (1)
  {
  }
}

3. 下载验证

编译无误下载到开发板后,打开串口调试助手,串口输出串口中断和定时器中断开启成功信息;按下K_UP和K_DOWN按键,可以依次对LED1/LED2的亮灭状态进行翻转;串口中输入字符串“LED3on、LED3off、LED4on、LED4off”可以控制LED3/LED4的亮灭并打印出相应的调试信息

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32是一款32位嵌入式微控制器系列,其中HAL(硬件抽象层)是一个软件库,用于与STM32微控制器的硬件进行高级的交互操作。FreeRTOS(实时操作系统)是一个开源的实时操作系统内核,用于实现多任务处理和任务调度。串口消息队列是HAL和FreeRTOS的结合应用,用于实现串口通信过程中的消息传递和任务调度。 在STM32中,通过HAL库中的串口接口可以实现与其他设备的串口通信。而使用FreeRTOS的串口消息队列,可以将串口接收到的消息经过处理后,以队列形式存储,等待任务调度进行处理。该消息队列可以是有大小限制的,根据实际需求进行设置。 当串口收到消息时,HAL库会触发中断,将接收到的数据存储到缓冲区中。然后,通过FreeRTOS的任务和队列机制,将数据从缓冲区移动到消息队列中。任务可以从消息队列中获取消息,并进行处理,例如解析数据、执行相应的操作等。 在使用STM32 HAL与FreeRTOS的串口消息队列时,需要注意以下几点: 1. 配置串口参数:使用HAL库的API函数配置串口的通信参数,如波特率、数据位、停止位等。 2. 创建任务:使用FreeRTOS的任务创建函数创建串口任务,指定任务优先级和任务堆栈大小。 3. 创建消息队列:使用FreeRTOS消息队列创建函数创建串口消息队列,指定消息队列的长度和消息大小。 4. 中断处理:在串口中断中,通过HAL库提供的函数将接收到的数据存储到缓冲区中。 5. 任务调度:使用FreeRTOS的任务调度机制,从缓冲区中将数据移动到消息队列中,并让任务从消息队列中获取消息进行处理。 6. 数据处理:任务从消息队列中获取消息后,根据消息进行相应的数据处理和操作。 通过STM32 HAL与FreeRTOS的串口消息队列,可以实现高效的串口通信和任务调度。这样可以将不同的串口任务分配给不同的任务进行处理,提高系统的实时性和并行处理能力。同时,通过消息队列机制,可以避免数据的丢失和冲突,提高系统的稳定性和可靠性。 ### 回答2: stm32是一款基于ARM Cortex-M处理器的微控制器系列,具有强大的性能和丰富的外设功能。HAL (Hardware Abstraction Layer)是一种抽象硬件层,提供了简化外设驱动程序编写的API接口。FreeRTOS是一款开源的实时操作系统,能够提供任务调度和同步机制。 在使用stm32 hal freertos时,可以通过串口消息队列来实现任务间的通信。消息队列是一种先进先出的数据结构,用于在任务之间传递数据。 首先,需要初始化一个消息队列,通过调用FreeRTOS提供的API函数来创建。可以指定队列的大小和每个消息的大小。 然后,可以在发送任务中使用hal库提供的串口发送函数,将需要传递的消息发送给消息队列。发送任务可以使用FreeRTOS提供的队列发送函数来向消息队列发送消息。 接收任务可以使用hal库提供的串口接收函数,然后调用FreeRTOS提供的队列接收函数来从消息队列中接收消息。 通过消息队列,发送任务可以将消息放入队列,接收任务可以从队列中获取消息。这样就实现了任务间的通信。 需要注意的是,由于消息队列是有限大小的,当队列已满时,发送任务可能会被阻塞。类似地,当队列为空时,接收任务可能会被阻塞。因此,在使用串口消息队列时,需要合理地设计队列的大小,以免造成问题。 总之,通过使用stm32 hal freertos和串口消息队列,可以方便地实现任务间的通信,实现数据的传递和处理。这对于复杂的嵌入式系统开发是非常有用的。 ### 回答3: stm32是一种微控制器品牌,HAL(Hardware Abstraction Layer)是一种硬件抽象层,FreeRTOS是一款开源的实时操作系统。 在使用stm32微控制器时,我们可以使用HAL库来简化与硬件的交互。针对串口通信,HAL库提供了一系列的函数,使我们可以方便地通过串口与其他设备进行数据传输。 而FreeRTOS则可以帮助我们实现任务调度和管理。在使用串口进行数据传输时,我们可以利用FreeRTOS提供的消息队列特性来实现线程间的高效通信。 消息队列是一种用来在不同任务之间传递数据的机制。当一个任务需要发送数据时,它可以将数据封装成一个消息并将其发送到消息队列中。其他任务可以从消息队列中接收消息,并根据接收到的消息做出相应的处理。 使用HAL库和FreeRTOS时,我们可以通过以下步骤来实现串口消息队列: 1. 初始化串口:使用HAL库中的函数初始化串口,设置好串口的参数和通信速率。 2. 创建消息队列:使用FreeRTOS中的函数创建一个消息队列,设置好队列的长度和消息的大小。 3. 发送消息:在需要发送数据的任务中,使用FreeRTOS提供的函数将数据封装成消息,并将消息发送到消息队列中。 4. 接收消息:在需要接收数据的任务中,使用FreeRTOS提供的函数从消息队列中接收消息,并根据接收到的消息进行处理。 通过以上步骤,我们可以实现多个任务之间的串口通信,并且保证数据的安全传输和高效处理。 总结起来,使用stm32的HAL库和FreeRTOS消息队列特性,可以方便地实现串口通信,并且保证多任务间的高效通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值