利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(2.1) —— 任务挂起和恢复

发布时间:2024年01月23日

前言

(1)FreeRTOS是我一天过完的,由此回忆并且记录一下。个人认为,如果只是入门,利用STM32CubeMX是一个非常好的选择。学习完本系列课程之后,再去学习网上的一些其他课程也许会简单很多。
(2)本系列课程是使用的keil软件仿真平台,所以对于没有开发板的同学也可也进行学习。
(3)叠甲,再次强调,本系列课程仅仅用于入门。学习完之后建议还要再去寻找其他课程加深理解。
(4)本系列博客对应代码仓库:

实操

(1)依旧是将上一篇博客的工程复制一份下来

在这里插入图片描述

任务挂起和恢复的宏

(1)如果需要调用任务挂起和恢复的函数,需要在FreeRTOSConfig.h文件中确认INCLUDE_vTaskSuspend 这个宏被置1了。

在这里插入图片描述

任务挂起和恢复代码实现

(1)在StartCubemxTask函数中进行如下补充即可。(按Ctrl+F搜索StartCubemxTask即可找到任务函数)

/* USER CODE END Header_StartCubemxTask */
void StartCubemxTask(void *argument)
{
  /* USER CODE BEGIN StartCubemxTask */
	char *CubemxTaskPrintf = (char *)argument;
	uint8_t Task_Status = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14) == GPIO_PIN_SET)
		{
			printf(CubemxTaskPrintf);
			Task_Status++;
			while(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14) == GPIO_PIN_SET);
		}
		switch(Task_Status)
		{
			case 1:
					// 挂起 keilTask 任务
					vTaskSuspend(keilTaskHandle);					
				break;
			case 2:
					// 恢复 keilTask 任务
					vTaskResume(keilTaskHandle);			
				break;
			default:
				Task_Status = 0;
				break;
		}
  }
  /* USER CODE END StartCubemxTask */
}

测试结果

(1)因为这里不会修改STM32CubeMX,所以keil的模拟器配置都还在,因此可以直接开始测试。
(2)测试结果发现,StartKeilTask Creat的字符串只会打印一次。而不是像任务删除和创建那样,每进行一次删除和创建都会打印一次StartKeilTask Creat

在这里插入图片描述

理论

FreeRTOS的4种任务状态

(1)首先我先介绍一下FreeRTOS的4种任务状态都是什么意思:
<1>Running 运行态: 当任务处于实际运行状态称之为运行态,即CPU的使用权被这个任务占用(对于单核处理器,同一时间仅一个任务处于运行态。后续会讲解RTOS的多任务执行原理)。
<2>Ready 就绪态: 处于就绪态的任务是指那些能够运行(没有被阻塞和挂起),但是当前没有运行的任务,因为同优先级或更高优先级的任务正在运行。
<3>Blocked 阻塞态: 如果一个任务因延时,或等待信号量、消息队列、事件标志组等而处于的状态被称之为阻塞态。当出现特定的事件发生,会自动进入就绪态。
<4>Suspended 挂起态: 任务暂停,必须手动调用xTaskResume()函数才可以进入就绪态。
(2)因为网上的FreeRTOS的4种任务切换图都是纯英文的,我于是就自己画了一个。这里简单介绍一下:
<1>进入就绪态: 当我们创建了一个任务之后,他就会进入就绪态,等待任务调度。
<2>就绪态和运行态切换: 就绪态和运行态的切换是由FreeRTOS的任务调度器进行切换的,我们人为无法改变。
<3>就绪态和阻塞态切换: 当发生特定的任务时候,任务会自动从阻塞态进入就绪态。例如任务延时结束,成功获取到了信号量、消息队列、事件标志组等信息。(听不懂别慌,后面讲同步互斥与通信的时候会详细讲解)
<4>就绪态和挂起态切换:

  • 当运行中的任务调用vTaskSuspend()函数,并在这个函数中传入需要挂起的任务句柄,那么这个处于就绪态的任务将会变为挂起态。
  • 当运行中的任务调用vTaskResume()函数,并在这个函数中传入需要从挂起态进入就绪态的任务句柄,那么这个处于挂起态的任务将会变为就绪态。

<5>运行态和挂起态切换: 当运行中的任务调用vTaskSuspend(NULL)的时候,就能够从运行态进入挂起态。
<6>运行态和阻塞态切换: 调用相关的阻塞API接口,例如vTaskDelay()vTaskDelayUntil() 这种延时函数,或者是信号量、消息队列或事件组等机制的一些函数。
<7>挂起态和阻塞态切换: 当运行中的任务调用vTaskSuspend()函数,并在这个函数中传入需要挂起的任务句柄,那么这个处于阻塞态的任务将会变为挂起态。

在这里插入图片描述

eTaskGetState()函数介绍

(1)获取任务状态

/**
 * @brief  获取任务状态
 *
 * @param  需要获取任务状态的任务句柄
 *
 * @return  eRunning   任务处于Running运行态
 *         -eReady     任务处于Ready就绪态
 *         -eBlocked   任务处于Blocked阻塞态
 *         -eSuspended 任务处于Suspended挂起态
 *         -eDeleted   任务的结构正在等待清理
 */
eTaskState eTaskGetState( TaskHandle_t xTask );

vTaskSuspend()函数介绍

(1) vTaskSuspend()用于挂起(暂停)任务,传入对应的任务句柄即可。
(2)如果需要挂起(暂停),那么就传入NULL

/**
 * @brief  挂起(暂停)的任务
 *
 * @param  要挂起(暂停)任务的任务句柄,如果是挂起(暂停)自己,传入NULL
 *
 * @return 无
 */
void vTaskSuspend( TaskHandle_t xTaskToSuspend );

vTaskResume()函数介绍

(1)vTaskResume()用于恢复被挂起(暂停)任务,传入对应的任务句柄即可。
(2)担心有小白问出一些抽象的问题,比如,为什么可以自己挂起自己,而不能自己恢复自己呢?你想想,任务都挂起了,根本就无法执行,你还自己恢复自己,咋想的?

/**
 * @brief  恢复的任务
 *
 * @param  要恢复任务的任务句柄
 *
 * @return 无
 */
void vTaskResume( TaskHandle_t xTaskToResume );

参考

(1)FreeRTOS官方文档:vTaskSuspend函数介绍
(2)FreeRTOS官方文档:vTaskResume函数介绍
(3)FreeRTOS官方API文档

文章来源:https://blog.csdn.net/qq_63922192/article/details/134559083
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。