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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值