STM32FreeRtos入门(四)——任务状态和调度

文章目录


前言

前面讲述了任务创建和任务删除

但是系统还缺少了最主要的任务调度,状态,优先级等。这章讲优先级


提示:以下是本篇文章正文内容,下面案例可供参考

一、任务状态


举例:打游戏

创建:打开,运行游戏

Running :进入对局,正在进行游玩的对局
Ready :匹配中,等待进入对局/掉线了等待重连。
Blocked :服务器维护,暂时玩不了。等待服务器恢复才能继续游玩

所以,Blocked 下一状态是Ready
Suspended :玩不下去游戏,上厕所,打电话,睡着了等等。但是后台还挂着。恢复了继续玩。同上,下一状态是Ready
Deleted:关闭游戏

示例代码

c 复制代码
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
	uint8_t dev, data;
    int len;
	int status;
	
	TaskHandle_t xSoundTaskHandle = NULL;
	BaseType_t ret;
	
  LCD_Init();
  LCD_Clear();
  
	
    IRReceiver_Init();
	LCD_PrintString(0,0,"Waiting music");
    while (1)
    {
					/* 读取红外遥控器,创建播放任务或者删除播放任务 */	
			if(0==IRReceiver_Read(&dev,&data))
			{
				if(data==0xa8)
				{
					extern void PlayMusic(void *params);
					if(xSoundTaskHandle==NULL)
					{
						LCD_ClearLine(0,0);
						LCD_PrintString(0,0,"Create music");
				  	ret = xTaskCreate(PlayMusic, "SoundTask", 128, NULL, osPriorityNormal, &xSoundTaskHandle);
						status=1;
					}
					else
					{
						if(status)
						{
						/*暂停或恢复*/
						LCD_ClearLine(0,0);
						LCD_PrintString(0,0,"Suspend music");
						vTaskSuspend(xSoundTaskHandle);
						PassiveBuzzer_Control(0);
							status=0;
						}
						else
						{
						LCD_ClearLine(0,0);
				    	LCD_PrintString(0,0,"Resume music");
						vTaskResume(xSoundTaskHandle);
							status=1;
						}
					}
				}
				
				else if(data==0xa2)
				{
					if(xSoundTaskHandle!=NULL)
					{
					LCD_ClearLine(0,0);
					LCD_PrintString(0,0,"Delete music");
					vTaskDelete(xSoundTaskHandle);
					PassiveBuzzer_Control(0);
					xSoundTaskHandle=NULL;
					}
				}	
			}
    }
  /* USER CODE END StartDefaultTask */
}

二、任务调度

调度,肯定就是任务之间的切换,包括延时等
FreeRTOS 是基于优先级的抢占式调度器,核心原则是:始终运行就绪态中优先级最高的任务。

  1. 调度策略
    抢占式调度:高优先级任务就绪时,会立即抢占低优先级任务的处理器资源(低优先级任务被暂停,进入就绪态)。
    时间片调度(同优先级任务):若多个任务优先级相同且均为就绪态,调度器会按时间片(由 configTICK_RATE_HZ 定义的系统节拍周期)轮流调度它们,实现 "并发" 效果。
  2. 调度触发时机
    系统节拍中断:由定时器产生的周期性中断(SysTick),是最常见的调度触发点(如任务延时到期、时间片轮转)。
    任务状态变化:如高优先级任务从阻塞态转为就绪态、任务主动调用 taskYIELD() 放弃处理器等。
    中断服务程序(ISR):ISR 中释放资源(如信号量)可能导致高优先级任务就绪,此时需调用 portYIELD_FROM_ISR() 触发调度。

1.函数说明

代码如下(示例):

  1. 任务创建与删除
    xTaskCreate() 创建一个新的任务并将其添加到就绪列表(动态内存分配,依赖 configSUPPORT_DYNAMIC_ALLOCATION 配置)。参数包括任务函数、任务名、栈大小、参数、优先级、任务句柄(输出)。
    xTaskCreateStatic() 静态创建任务(需手动指定栈和任务控制块内存,不依赖动态内存,依赖 configSUPPORT_STATIC_ALLOCATION)。
    vTaskDelete() 删除指定任务,被删除的任务将从就绪 / 阻塞 / 挂起列表中移除,其资源(若动态分配)会在空闲任务中释放。
  2. 任务阻塞与延时
    vTaskDelay() 让当前任务进入阻塞状态一段指定时间(以系统节拍 tick 为单位),时间到后自动进入就绪态。注意:延时是 "相对时间",从调用时刻开始计算。
    vTaskDelayUntil() 让任务按照 "绝对时间" 周期性阻塞(适合需要固定周期执行的任务),确保任务执行间隔稳定,不受调度延迟影响。
    xTaskAbortDelay() 强制唤醒一个因 vTaskDelay()、vTaskDelayUntil() 或阻塞在信号量 / 队列等上的任务,使其立即进入就绪态。
  3. 任务优先级管理
    vTaskPrioritySet() 动态修改指定任务的优先级。
    uxTaskPriorityGet() 获取指定任务的当前优先级。
    vTaskPriorityInherit() / vTaskPriorityDisinherit() 用于互斥锁(xSemaphoreCreateMutex())的优先级继承机制,防止优先级反转(自动提升低优先级任务的优先级)。
  4. 任务挂起 / 恢复的扩展
    vTaskSuspendAll() 挂起所有任务(包括调度器),仅允许当前任务运行,直到调用 xTaskResumeAll() 恢复。注意:此函数不挂起中断,且期间不能调用可能引起上下文切换的函数(如 vTaskDelay())。
    xTaskResumeAll() 恢复被 vTaskSuspendAll() 挂起的所有任务和调度器,返回值指示恢复期间是否有任务需要运行(pdTRUE 表示需要上下文切换)。
    xTaskResumeFromISR() 在中断服务程序(ISR)中恢复被挂起的任务,返回值为 pdTRUE 时需触发上下文切换(通过 portYIELD_FROM_ISR())。
  5. 任务状态查询
    eTaskGetState() 获取指定任务的当前状态(如运行、就绪、阻塞、挂起等,返回 eTaskState 枚举值)。
    uxTaskGetNumberOfTasks() 获取当前系统中存在的任务总数(包括所有状态的任务)。
    vTaskList() 生成任务状态列表字符串(包含任务名、状态、优先级、栈剩余空间等信息),需配置 configUSE_TRACE_FACILITY 为 1。
  6. 调度器控制
    vTaskStartScheduler() 启动 FreeRTOS 调度器,开始任务调度(通常在 main() 中初始化所有任务后调用)。
    vTaskEndScheduler() 停止调度器并释放所有资源(仅部分平台支持,如 x86,嵌入式平台较少使用)。
  7. 任务切换触发
    taskYIELD() 强制当前任务放弃 CPU 使用权,触发一次上下文切换(让就绪态中最高优先级的任务运行)。
    portYIELD_FROM_ISR() 在中断服务程序中触发上下文切换(需配合 xTaskResumeFromISR() 等函数的返回值使用)。

这些函数共同构成了 FreeRTOS 的任务调度机制,使用时需结合具体场景(如是否在中断中、是否需要动态内存、任务优先级设计等),并确保配置项(FreeRTOSConfig.h)与函数功能匹配。

2.任务调度

前面讲了,删除任务必须自杀或者他杀;

c 复制代码
void Led_Test(void)
{
	int i;
    Led_Init();
    for(i=0;i<10;i++)
    {
        Led_Control(LED_GREEN, 1);
        mdelay(500);
        Led_Control(LED_GREEN, 0);
        mdelay(500);
    }
		vTaskDelete(NULL);//不自杀或者他杀,系统崩溃
}

任务他杀后,"收尸"(释放TCB,回收栈)工作由执行他杀任务清除。自杀后,由空闲任务进行"收尸"(释放TCB,回收栈), 若一直没有空闲任务进行"收尸",则栈被使用完,系统崩溃

编程习惯可以尽量避免这种情况;

1,事件驱动

2,延时函数不要用死循环

c 复制代码
void Led_Test(void)
{
	int i;
    Led_Init();
    for(i=0;i<10;i++)
    {
        Led_Control(LED_GREEN, 1);
        //mdelay(500);
        vTaskDelay(500);
        Led_Control(LED_GREEN, 0);
        //mdelay(500);
	 	vTaskDelay(500);
    }
		vTaskDelete(NULL);//不自杀或者他杀,系统崩溃
}

自杀后,由空闲任务进行"收尸"(释放TCB,回收栈)

调度器函数中会自己创建空闲任务

3.延时函数区别

vTaskDelay()让当前任务从就绪态进入阻塞状态一段指定时间

使用此函数,系统任务切换延时时间近乎于指定时间

vTaskDelayUntil()让任务按照 "绝对时间" 周期性阻塞,确保任务执行间隔稳定,不受调度延迟影响。

vTaskDelayUntil(&PreTime,500);

系统任务切换时间间隔不确定,为了前面的if部分,使延时总体为500ms

c 复制代码
void LcdPrintTask(void *params)
{
	struct TaskPrintInfo *pInfo = params;
	uint32_t cnt = 0;
	int len;
	BaseType_t PreTime;
	uint64_t t1,t2;
	
	PreTime=xTaskGetTickCount();
	while (1)
	{
		/* 打印信息 */
		if (g_LCDCanUse)
		{
			g_LCDCanUse = 0;
			len = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name);
			len += LCD_PrintString(len, pInfo->y, ":");
			LCD_PrintSignedVal(len, pInfo->y, cnt++);
			g_LCDCanUse = 1;
			mdelay(cnt & 0x3);
		}
		t1=system_get_ns();
		//vTaskDelay(500);
		vTaskDelayUntil(&PreTime,500);
		t2=system_get_ns();
		LCD_ClearLine(pInfo->x, pInfo->y+2);
		LCD_PrintSignedVal(pInfo->x, pInfo->y+2,t2-t1);
	}
}

总结

FreeRTOS 通过优先级抢占和时间片调度实现高效的任务管理,任务状态的切换由事件(如延时、信号量)和调度器共同控制。理解这些机制是使用 FreeRTOS 进行多任务编程的基础。
FreeRTOS 是基于优先级的抢占式调度器,核心原则是:始终运行就绪态中优先级最高的任务。

相关推荐
东木君_9 分钟前
芯外拾遗第二篇:编译、工具链、烧录,你真的搞懂了吗?
linux·单片机·操作系统·嵌入式
laocooon5238578861 小时前
运行当前位置,显示文件全名,检查是否扩展名多次重叠
stm32·单片机·嵌入式硬件
沉醉不知归路11 小时前
cursor导入keil工程详细步骤
stm32
D.....l2 小时前
STM32学习(MCU控制)(I2C 模拟)
stm32·单片机·学习
国科安芯2 小时前
基于ASM1042通信接口芯片的两轮车充电机性能优化研究
服务器·网络·人工智能·单片机·嵌入式硬件·性能优化
A9better3 小时前
嵌入式开发学习日志42——stm32之SPI工作方式
stm32·单片机·嵌入式硬件·学习
盈创力和20073 小时前
以太网多参量传感器:工业物联网时代的安全监测革新
嵌入式硬件·物联网·安全·以太网温湿度传感器·多参量传感器·以太网多参量传感器
qqxhb3 小时前
系统架构设计师备考第60天——嵌入式硬件体系&软件架构
单片机·嵌入式硬件·系统架构·存储器·处理器·可裁剪·强实时
D.....l4 小时前
STM32学习(MCU控制)(SysTick and TIM)
stm32·单片机·学习
盈创力和20075 小时前
以太网多参量传感器:构筑工业安全与环境稳定的“数据堡垒”
嵌入式硬件·安全·以太网温湿度传感器·多参量传感器