欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > FreeRTOS基础入门——任务挂起和恢复API函数(六)

FreeRTOS基础入门——任务挂起和恢复API函数(六)

2024/10/24 18:23:09 来源:https://blog.csdn.net/m0_63168877/article/details/141027079  浏览:    关键词:FreeRTOS基础入门——任务挂起和恢复API函数(六)

 个人名片:

🎓作者简介:嵌入式领域优质创作者
🌐个人主页:妄北y

📞个人QQ:2061314755

💌个人邮箱:[mailto:2061314755@qq.com]
📱个人微信:Vir2025WBY

🖥️个人公众号:科技妄北
🖋️本文为妄北y原创佳作,独家首发于CSDN🎊🎊🎊
💡座右铭:改造世界固然伟大,但改造自我更为可贵。

专栏导航:

妄北y系列专栏导航:

物联网嵌入式开发项目:大学期间的毕业设计,课程设计,大创项目,各种竞赛项目,全面覆盖了需求分析、方案设计、实施与调试、成果展示以及总结反思等关键环节。📚💼💡

QT基础入门学习:对QT的基础图形化页面设计进行了一个简单的学习与认识,利用QT的基础知识进行了翻金币小游戏的制作。🛠️🔧💭

Linux基础编程:初步认识什么是Linux,为什么学Linux,安装环境,进行基础命令的学习,入门级的shell编程。🍻🎉🖥️

深耕Linux应用开发:分享Linux的基本概念、命令行操作、文件系统、用户和权限管理等,网络编程相关知识,TCP/IP 协议、套接字(Socket)编程等,可以实现网络通信功能。常见开源库的二次开发,如libcurl、OpenSSL、json-c、freetype等💐📝💡

Linux驱动开发:Linux驱动开发是Linux系统不可或缺的组成部分,它专注于编写特殊的程序——驱动程序。这些程序承载着硬件设备的详细信息,并扮演着操作系统与硬件间沟通的桥梁角色。驱动开发的核心使命在于确保硬件设备在Linux系统上顺畅运作,同时实现与操作系统的无缝集成,为用户带来流畅稳定的体验。🚀🔧💻

Linux项目开发:Linux基础知识的实践,做项目是最锻炼能力的一个学习方法,这里我们会学习到一些简单基础的项目开发与应用,而且都是毕业设计级别的哦。🤸🌱🚀

非常期待与您一同在这个广阔的互联网天地里,携手探索知识的海洋,互相学习,共同进步。🌐💫🌱 熠熠星光,照亮我们的成长之路

✨✨ 欢迎订阅本专栏,对专栏内容任何问题都可以随时联系博主,共同书写属于我们的精彩篇章!✨✨

文章介绍:

📚本篇文章将深入剖析FreeRTOS学习的精髓与奥秘,与您一同分享相关知识!🎉🎉🎉

若您觉得文章尚可入目,期待您能慷慨地送上点赞、收藏与分享的三连支持!您的每一份鼓励,都是我创作路上源源不断的动力。让我们携手并进,共同奔跑,期待在顶峰相见的那一天,共庆辉煌!🚀🚀🚀

🙏衷心感谢大家的点赞👍、收藏⭐和评论✍️,您的支持是我前进的动力!

目录:

目录:

一、任务挂起与恢复

1.1 函数vTaskSuspend()

1.1.1 参数: 

1.1.2 返回值:

1.1.3 使用说明:

1.1.4 注意事项:

1.2 函数vTaskResume()

1.2.1 参数:

1.2.2 返回值:

1.2.3 使用说明:

1.2.4 注意事项:

1.3  函数xTaskResumeFromISR()

1.3.1 参数:

1.3.2 返回值:

1.3.3 使用说明:

1.3.4 注意事项:

二、程序设计

2.1 设计目的:

2.1.1 任务设计:

2.1.2 按键设计:

2.2 实验程序分析:

2.2.1 任务设置:

2.2.2 main()函数:

2.2.3 任务函数:

三、程序结果分析:


一、任务挂起与恢复

在某些情况下,我们可能需要暂时暂停一个任务的执行,然后在一段时间后重新启动它。如果我们选择删除任务并重新创建,这样会导致任务中所保存的变量值丢失。为了解决这个问题,FreeRTOS提供了任务挂起和恢复的机制

当一个任务需要暂停运行时,可以将其挂起;待到需要恢复该任务时,再进行恢复。FreeRTOS中提供了相关的API函数来实现任务的挂起和恢复,具体的函数可以参考表。

1.1 函数vTaskSuspend()

vTaskSuspend 函数是 FreeRTOS 中用于挂起任务的一个重要函数

void vTaskSuspend(TaskHandle_t xTaskToSuspend);

1.1.1 参数: 

xTaskToSuspend: 指向要挂起的任务的任务句柄。每个创建的任务都有一个唯一的任务句柄,可以在创建任务时通过 xTaskCreatexTaskCreateStatic 获得该句柄。

如果使用函数xTaskCreate()创建任务的话那么函数的参数 pxCreatedTask就是此任务的任务句柄,如果使用函数xTaskCreateStatic() 创建任务的话那么函数的返回值就是此任务的任务句柄

也可以使用 xTaskGetHandle 函数根据任务名称获取任务句柄。

1.1.2 返回值:

此函数没有返回值。

1.1.3 使用说明:

挂起任务: 调用 vTaskSuspend() 函数后,指定的任务将进入挂起状态。处于挂起状态的任务不会被调度运行,直到它被恢复。

恢复任务: 要恢复处于挂起状态的任务,您需要调用 vTaskResume()xTaskResumeFromISR()只有通过这些函数,任务才能退出挂起状态。

1.1.4 注意事项:

使用任务句柄时,需要确保句柄有效,如果句柄无效,调用 vTaskSuspend() 可能会导致未定义行为。

如果参数为NULL的话表示挂起任务自己。

1.2 函数vTaskResume()

vTaskResume 函数是 FreeRTOS 中用于将一个挂起的任务恢复到就绪状态的函数。

void vTaskResume(TaskHandle_t xTaskToResume);

1.2.1 参数:

xTaskToResume: 这是一个任务句柄,指向要恢复的任务。该任务必须之前通过 vTaskSuspend 或 vTaskSuspendAll 方法被挂起。

1.2.2 返回值:

此函数没有返回值。

1.2.3 使用说明:

只有通过 vTaskSuspend 函数挂起的任务才能使用 vTaskResume 恢复。

如果尝试恢复一个未挂起的任务,函数不会产生任何效果。

使用此函数时,确保传入的任务句柄有效,以避免不确定的行为。

1.2.4 注意事项:

任务的优先级和调度策略将决定恢复后的调度行为。如果有多个就绪任务,调度器将根据优先级选择下一个要运行的任务。

在多核系统中,注意任务的运行可能会被分配到不同的核心。

1.3  函数xTaskResumeFromISR()

xTaskResumeFromISR 函数是 FreeRTOS 中用于在中断服务例程 (ISR) 中恢复一个挂起任务的函数。

BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume);

1.3.1 参数:

xTaskToResume: 这是一个任务句柄,指向要恢复的任务。该任务必须之前通过 vTaskSuspend 或 vTaskSuspendAll 方法被挂起。

1.3.2 返回值:

pdTRUE: 表示恢复的任务的优先级等于或高于当前正在运行的任务(即被中断打断的任务)。这意味着在退出中断服务例程后必须进行一次上下文切换。

pdFALSE: 表示恢复的任务的优先级低于当前正在运行的任务。这意味着在退出中断服务例程后不需要进行上下文切换。

1.3.3 使用说明:

xTaskResumeFromISR 适用于需要在中断上下文中恢复任务的场景,例如在接收到中断信号后需要唤醒某个任务来处理数据。

在 ISR 中调用该函数时,应注意中断的优先级,确保不会导致优先级反转或其他调度问题。

使用此函数时需要根据返回值决定是否需要在 ISR 退出时调用 taskYIELD() 或相应的上下文切换处理,以确保新的优先级任务能够被调度。

1.3.4 注意事项:

由于 ISR 的特性,xTaskResumeFromISR 不会直接进行上下文切换,而是通过返回值指示是否需要在 ISR 结束时进行切换。

确保在 ISR 中的任务恢复操作是快速和高效的,以避免影响系统的实时性能。

二、程序设计

2.1 设计目的:

学习使用FreeRTOS的任务挂起和恢复相关API函数,包括VTaskSuspend()、VTaskResume()
和xTaskResumeFromISR()。

本设计的目标是利用 FreeRTOS 的任务管理功能,创建和管理多个任务,并通过按键控制这些任务的挂起和恢复。

2.1.1 任务设计:

1. Start Task:

  • 功能: 负责创建其他任务(key_task、task1_task 和 task2_task)。
  • 作用: 作为系统的起始点,确保其他任务的初始化和运行,以便后续的按键操作可以被正确处理。

2. Key Task:

  • 功能: 负责检测按键输入。根据不同按键的状态执行相应的操作。
  • 作用: 作为系统的主控制逻辑,识别用户的输入并决定如何响应,从而影响其他任务的状态。

3. Task1 Task:

  • 功能: 执行应用逻辑1。
  • 作用: 具体的业务逻辑或功能,可能涉及数据处理、状态更新等。

4. Task2 Task:

  • 功能: 执行应用逻辑2。
  • 作用: 另一种业务逻辑或操作,可能与 Task1 的功能有所不同。

2.1.2 按键设计:

1. KEY0:

  • 功能: 中断模式,恢复 Task2 的运行。
  • 分析: 通过中断服务程序快速响应按键事件,适合需要即时处理的场景。该按键的使用可以使 Task2 在适当时刻恢复运行,处理可能的事件或数据。

2. KEY1:

  • 功能: 输入模式,恢复 Task1 的运行。
  • 分析: 可以通过主控制逻辑(Key Task)来实现,适用于需要用户主动操作的情况。当用户按下该键时,Task1 将被恢复,以继续其工作。

3. KEY2:

  • 功能: 输入模式,挂起 Task2 的运行。
  • 分析: 允许用户通过按键控制 Task2 的执行,可能用于暂停某些操作以避免资源冲突或处理优先级问题。

4. KEY UP:

  • 功能: 输入模式,挂起 Task1 的运行。
  • 分析: 类似于 KEY2,但控制的是 Task1,这表明系统可能需要根据当前状态动态调整任务的执行,以优化资源使用和响应时间。

通过设计四个任务和四个按键,实现了较为灵活的任务管理机制。任务之间的相互控制提供了系统对外部事件的响应能力,特别是在多任务环境中,通过挂起和恢复任务来动态调整系统行为。

2.2 实验程序分析:

2.2.1 任务设置:

设计中任务优先级、堆栈大小和任务句柄等的设置如下:

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define KEY_TASK_PRIO		2
//任务堆栈大小	
#define KEY_STK_SIZE 		128  
//任务句柄
TaskHandle_t KeyTask_Handler;
//任务函数
void key_task(void *pvParameters);//任务优先级
#define TASK1_TASK_PRIO		3
//任务堆栈大小	
#define TASK1_STK_SIZE 		128  
//任务句柄
TaskHandle_t Task1Task_Handler;
//任务函数
void task1_task(void *pvParameters);//任务优先级
#define TASK2_TASK_PRIO		4
//任务堆栈大小	
#define TASK2_STK_SIZE 		128  
//任务句柄
TaskHandle_t Task2Task_Handler;
//任务函数
void task2_task(void *pvParameters);

2.2.2 main()函数:

int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 delay_init();	    				//延时函数初始化	 uart_init(115200);					//初始化串口LED_Init();		  					//初始化LEDKEY_Init();							//初始化按键EXTIX_Init();						//初始化外部中断LCD_Init();							//初始化LCDPOINT_COLOR = RED;LCD_ShowString(30,10,200,16,16,"ATK STM32F103/407");	LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 6-3");LCD_ShowString(30,50,200,16,16,"Task Susp and Resum");LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,90,200,16,16,"2016/11/25");//创建开始任务xTaskCreate((TaskFunction_t )start_task,            //任务函数(const char*    )"start_task",          //任务名称(uint16_t       )START_STK_SIZE,        //任务堆栈大小(void*          )NULL,                  //传递给任务函数的参数(UBaseType_t    )START_TASK_PRIO,       //任务优先级(TaskHandle_t*  )&StartTask_Handler);   //任务句柄              vTaskStartScheduler();          //开启任务调度
}

在main函数中我们主要完成硬件的初始化,在硬件初始化完成以后创建了任务start task()
并且开启了FreeRTOS的任务调度。

2.2.3 任务函数:

 1. 开始任务(start_task

//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           //进入临界区//创建KEY任务xTaskCreate((TaskFunction_t )key_task,             (const char*    )"key_task",           (uint16_t       )KEY_STK_SIZE,        (void*          )NULL,                  (UBaseType_t    )KEY_TASK_PRIO,        (TaskHandle_t*  )&KeyTask_Handler);  //创建TASK1任务xTaskCreate((TaskFunction_t )task1_task,             (const char*    )"task1_task",           (uint16_t       )TASK1_STK_SIZE,        (void*          )NULL,                  (UBaseType_t    )TASK1_TASK_PRIO,        (TaskHandle_t*  )&Task1Task_Handler);   //创建TASK2任务xTaskCreate((TaskFunction_t )task2_task,     (const char*    )"task2_task",   (uint16_t       )TASK2_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK2_TASK_PRIO,(TaskHandle_t*  )&Task2Task_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL();            //退出临界区
}
  • 功能: 负责初始化和创建其他三个任务。
  • 关键操作:
    • 临界区:
      • taskENTER_CRITICAL() 和 taskEXIT_CRITICAL() 用于保护任务创建过程,避免中断或任务调度影响创建过程。
    • 任务创建:
      • 使用 xTaskCreate 函数创建 key_tasktask1_task 和 task2_task,分别负责按键处理、执行任务1和任务2的逻辑。
      • 每个任务的栈大小和优先级由宏定义(如 KEY_STK_SIZETASK1_TASK_PRIO 等)指定。
    • 删除开始任务:
      • vTaskDelete(StartTask_Handler) 删除开始任务自身,释放资源。

2. 按键任务(key_task

//key任务函数
void key_task(void *pvParameters)
{u8 key,statflag=0;while(1){key=KEY_Scan(0);switch(key){case WKUP_PRES:statflag=!statflag;if(statflag==1){vTaskSuspend(Task1Task_Handler);//挂起任务printf("挂起任务1的运行!\r\n");}else if(statflag==0){vTaskResume(Task1Task_Handler);	//恢复任务1printf("恢复任务1的运行!\r\n");}		break;case KEY1_PRES:vTaskSuspend(Task2Task_Handler);//挂起任务2printf("挂起任务2的运行!\r\n");break;}vTaskDelay(10);			//延时10ms }
}
  • 功能: 监测按键状态,并控制其他任务的挂起与恢复。
  • 工作流程:
    • 无限循环:
      • KEY_Scan(0) 调用,获取当前按键状态。
      • 使用 switch 语句处理不同的按键输入:
        • WKUP_PRES:
          • 使用 statflag 切换状态:
            • 如果 statflag 为1,挂起 task1_task,并打印输出。
            • 如果 statflag 为0,恢复 task1_task,并打印输出。
        • KEY1_PRES:
          • 挂起 task2_task,并打印输出。
    • vTaskDelay(10) 用于防止忙等待,降低 CPU 占用率。

3. 任务1 (task1_task)

//task1任务函数
void task1_task(void *pvParameters)
{u8 task1_num=0;POINT_COLOR = BLACK;LCD_DrawRectangle(5,110,115,314); 	//画一个矩形	LCD_DrawLine(5,130,115,130);		//画线POINT_COLOR = BLUE;LCD_ShowString(6,111,110,16,16,"Task1 Run:000");while(1){task1_num++;	//任务执1行次数加1 注意task1_num1加到255的时候会清零!!LED0=!LED0;printf("任务1已经执行:%d次\r\n",task1_num);LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充区域LCD_ShowxNum(86,111,task1_num,3,16,0x80);	//显示任务执行次数vTaskDelay(1000);                           //延时1s,也就是1000个时钟节拍	}
}
  • 功能: 执行主逻辑,并定期进行状态更新。任务1的任务函数,用于观察任务挂起和恢复的过程。
  • 工作流程:
    • 初始化一些图形显示(如矩形和线)和文本。
    • 无限循环:
      • 每次执行时将 task1_num 递增,记录任务执行次数。
      • 切换 LED 状态以提供视觉反馈。
      • 打印任务执行次数到控制台。
      • 使用 LCD_Fill 和 LCD_ShowxNum 更新显示内容。
      • vTaskDelay(1000) 延迟 1 秒用于控制任务的执行频率。

4. 任务2 (task2_task)

//task2任务函数
void task2_task(void *pvParameters)
{u8 task2_num=0;POINT_COLOR = BLACK;LCD_DrawRectangle(125,110,234,314); //画一个矩形	LCD_DrawLine(125,130,234,130);		//画线POINT_COLOR = BLUE;LCD_ShowString(126,111,110,16,16,"Task2 Run:000");while(1){task2_num++;	//任务2执行次数加1 注意task1_num2加到255的时候会清零!!LED1=!LED1;printf("任务2已经执行:%d次\r\n",task2_num);LCD_ShowxNum(206,111,task2_num,3,16,0x80);  //显示任务执行次数LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域vTaskDelay(1000);                           //延时1s,也就是1000个时钟节拍	}
}
  • 功能: 和任务1类似,执行另一段逻辑。任务2的任务函数,用于观察任务挂起和恢复的过程(中断方式)。
  • 工作流程:
    • 初始化图形显示(矩形和线)和文本。
    • 无限循环:
      • 每次执行时将 task2_num 递增,记录任务2的执行次数。
      • 切换 LED 状态。
      • 打印任务2的执行次数。
      • 更新显示内容。
      • vTaskDelay(1000) 延迟 1 秒用于控制任务的执行频率。

5. 任务函数小结:

  • 任务管理: 通过创建多个任务,实现了对不同功能的模块化处理,确保系统的可扩展性和可维护性。
  • 按键控制: 通过按键任务动态控制任务的运行状态,增加了用户交互性。
  • 显示更新: 结合 LCD 显示,任务不仅仅是逻辑处理,还涉及到与用户的视觉交互。
  • 注意事项:
    • 在多任务环境中,需要注意优先级和资源共享,确保没有优先级反转或资源竞争的问题。
    • 中断和任务调度的结合使用要确保系统的实时性和稳定性。

三、程序结果分析:

编译并下载程序到开发板中,通过按不同的按键来观察任务的挂起和恢复的过程。

一开始任务1和任务2都正常运行,当挂起任务1或者任务2以后,任务1或者任务2就会停止运行,直到下一次重新恢复任务1或者任务2的运行。重点是,保存任务运行次数的变量都没有发生数据丢失,如果用任务删除和重建的方法这些数据必然会丢失掉的!
 

📝大佬觉得本文有所裨益,不妨轻点一下👍给予鼓励吧!

❤️❤️❤️本人虽努力,但能力尚浅,若有不足之处,恳请各位大佬不吝赐教,您的批评指正将是我进步的动力!😊😊😊

💖💖💖若您认为此篇文章对您有所帮助,烦请点赞👍并收藏🌟,您的支持是我前行的最大动力!

🚀🚀🚀任务在默默中完成,价值在悄然间提升。让我们携手共进,一起加油,迎接更美好的未来!🌈🌈🌈

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com