利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(2.0) —— 如何删除任务

发布时间:2024年01月23日

前言

(1)FreeRTOS是我一天过完的,由此回忆并且记录一下。个人认为,如果只是入门,利用STM32CubeMX是一个非常好的选择。学习完本系列课程之后,再去学习网上的一些其他课程也许会简单很多。
(2)本系列课程是使用的keil软件仿真平台,所以对于没有开发板的同学也可也进行学习。
(3)叠甲,再次强调,本系列课程仅仅用于入门。学习完之后建议还要再去寻找其他课程加深理解。
(4)本系列博客对应代码仓库:
(5)前面我们已经了解了如何创建任务,但是,如果有些任务我们并不是要一直执行,可能要根据情况进行删除任务。那么本文将会介绍如何如何对任务进行删除,但是需要注意,一般情况,删除任务用到少。因为任务自杀要考虑的方面很多,容易出问题,所以新手小白建议了解即可。

实战

(1)任务删除是非常简单的,但是他需要考虑很多问题,所以我不建议新手小白频繁的删除和创建任务。但是,为了保证知识的完整性,我依旧会对此进行讲解。
(2)在上一篇博客的工程基础上进行调整。

在这里插入图片描述

删除任务要注意的宏定义

(1)如果需要调用删除任务的函数,需要在FreeRTOSConfig.h文件种确认INCLUDE_vTaskDelete这个宏被置1了。

在这里插入图片描述

删除任务

(1)首先,我打算使用让GPIOC14引脚作为任务创建删除的控制引脚,因此需要在STM32CubeMX中将这个引脚设置为下拉输入。

在这里插入图片描述

(2)在StartCubemxTask函数中进行如下补充即可。(按Ctrl+F搜索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:
				if(keilTaskHandle != NULL)
				{
					// 删除 keilTask 任务
					vTaskDelete(keilTaskHandle);			
					keilTaskHandle = NULL;
				}					
				break;
			case 2:
				if(keilTaskHandle == NULL)
				{
					// 重新创建 keilTask 任务
					keilTaskHandle = xTaskCreateStatic(StartKeilTask,"KeilTask", 128, NULL, osPriorityLow1, g_pucStackKeilTaskBuff,&g_TCBKeilTask);
					if(keilTaskHandle == NULL)
					{
						printf("KeilTask creation failed\r\n");
					}		
				}					
				break;
			case 3:
				// 任务自杀
				CubemxTaskHandle = NULL;
				vTaskDelete(NULL);				
				break;
			default:
				Task_Status = 0;
				break;
		}
  }
  /* USER CODE END StartCubemxTask */
}

(3)在StartKeilTask函数中进行如下补充即可。(按Ctrl+F搜索Private application code即可找到任务函数)

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
int fputc(int ch, FILE *f)
{
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);
	return ch;
}
void StartKeilTask(void *argument)
{
	printf("StartKeilTask Creat\r\n");
	while(1)
	{
		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
		HAL_Delay(100);
	}
}
/* USER CODE END Application */

测试结果

keil调试配置

(1)打开微库。

在这里插入图片描述

(2)配置模拟器
DARMSTM.DLL
pSTM32F103C8

在这里插入图片描述

配置虚拟示波器

(1)打开调试界面

在这里插入图片描述

(2)选择逻辑分析仪,检测PC13引脚。为什么下面输入的是PORTC.13,原因很简单,格式为PORTx.yx表示端口,y表示具有引脚数值,注意’.'必须是英文的!

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

配置虚拟串口

(1)如下图

在这里插入图片描述

打开GPIO引脚电平配置界面

(1)因为我们需要模拟一个按下按键的操作,因此可以进行如下操作。

在这里插入图片描述

实测

(1)先全速跑

在这里插入图片描述

(2)勾选上PC14引脚。

在这里插入图片描述

(3)取消勾选PC14。

在这里插入图片描述

(4)勾选上PC14引脚。

在这里插入图片描述

(5)取消勾选PC14。

在这里插入图片描述

(6)再次进行电平翻转工作,之后无论怎么反转PC14的电平,我们会发现,方波会一直存在。因为第三次反转PC14的电平是进行任务自杀,所以最终不会有任何现象发生。

在这里插入图片描述

理论

vTaskDelete()函数介绍

(1)这个任务使用起来还是很容易的,只需要传入一个任务句柄即可。不过需要注意的是,删除任务有两种方式,第一种是删除其他的任务,第二种是任务自杀。
<1>删除其他任务:当你需要在任务A中删除任务B,只需要在任务A中调用任务B的句柄即可。如果任务B在创建的时候,任务句柄传入的是NULL,那么任务B将只能自杀,无法被其他任务杀死。
<2>任务自杀:任务自杀只需要传入一个NULL即可。

/**
 * @brief  RTOS 内核管理中移除任务
 *
 * @param  要移除任务的任务句柄,如果是任务自杀,传入NULL
 *
 * @return 无
 */
void vTaskDelete( TaskHandle_t xTaskToDelete );

两种任务删除要注意的点

(1)任务自杀通常由任务自己主动发起,而删除其他任务是由系统中的某个任务请求删除另一个任务。
(2)在实际应用中,需要根据具体的需求和设计来选择使用哪种方法。在任何情况下,都需要确保在删除任务之前,已经合理地释放了任务占用的资源,以避免资源泄漏和系统不稳定性。删除任务释放的资源要考虑以下内容:

  • 避免删除正在执行的任务:尽量避免删除正在执行的任务,因为这可能导致未定义的行为。通常,应该在目标任务主动结束执行或者在任务的代码中检查某些条件后再请求删除。
  • 处理资源释放:确保在删除任务之前释放任务使用的资源。这包括释放动态分配的内存、关闭文件句柄、释放占用的硬件资源等。如果任务在删除时仍然占用资源,可能会导致资源泄漏或系统不稳定。
  • 处理同步和互斥:如果目标任务与其他任务之间存在同步或互斥关系,确保在删除任务之前解除这些关系,以免引起竞态条件或死锁。
  • 避免删除空闲任务:在 FreeRTOS 中,空闲任务(Idle Task)用于在系统没有其他任务需要执行时运行。删除空闲任务可能导致系统无法正常工作,应该谨慎使用。例如,任务删除之后的堆栈释放,是在空闲任务中执行,当空闲任务删除之后,堆栈将需要通过其他任务手动释放,这样将会增加工作量。

重新创建任务需要注意的点

(1)其实从实操中已经知道了,当我们重新创建任务的时候。任务会从头执行,因此这里我们将能够看到两次StartKeilTask Creat到底字符数据打印。

在这里插入图片描述

参考

(1)FreeRTOS官方文档:vTaskDelete函数介绍

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