肥仔教程网

SEO 优化与 Web 开发技术学习分享平台

freeRTOS的钩子函数和空闲任务有什么区别?


最近做的项目用到freeRTOS,突发好奇关注了一下空闲任务和钩子函数,就想知道这两者到底用来干嘛,简单分享一下我自己的一些理解。

一、空闲任务

空闲任务是在 freeRTOS 系统启动之后就会被默认创建的一个任务,该任务的优先级是最低的。

空闲任务是一个比较特殊的任务,当系统中没有其他任务需要运行时,系统将会调度空闲任务来执行,保证系统有任务在运行着。

空闲任务的代码流程如下,感兴趣的朋友可以去看看:

OS_Start() --> vTaskStartScheduler() --> prvCreateIdleTasks() --> 任务函数在portTASK_FUNCTION( prvIdleTask, pvParameters )

空闲任务的实现涉及到几个关键步骤:

1)检查是否有任务需要被删除

2)处理与空闲任务同优先级的任务

3)执行空闲钩子函数(如果有定义的话)

4)在适当的情况下进入低功耗模式。

空闲任务的循环大致包含的内容如下所示:

for( ;; )
{
  // 检查是否有任务删除了自己
  prvCheckTasksWaitingTermination();


  // 如果有与空闲任务同优先级的任务,根据配置决定是否立即让出CPU
  if (listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1)
  {
    taskYIELD();
  }
 
  // 调用空闲钩子函数
  if( configUSE_IDLE_HOOK == 1 )
  {
    vApplicationIdleHook();
  }
 
  // 进入低功耗模式
  if( configUSE_TICKLESS_IDLE != 0 )
  {
    // 其他的代码省略。。。
  }
}

分析空闲任务的代码可以知道,空闲任务会负责释放一些被删除任务的内存,甚至包括用户主动分配的内存通常也是在空闲任务中释放的。

一般来说,如果涉及到一些系统资源的释放或者内存的回收之类的,建议放到空闲任务中去执行,这样可以确保在系统没有其他的人需要运行的任务时,内存能及时得到释放。

总的来说,空闲任务在系统中很重要,它的存在就是要保证系统处于“忙碌”状态的,任何时候都要保证系统有可被执行的任务。

空闲任务的职责可归纳为:

(1)内存管理:

空闲任务负责释放那些已经被删除的任务的资源,包括任务的堆栈和任务控制块(TCB)。

这是通过检查是否有任务删除了自己并由空闲任务来清理资源来实现的。

(2)处理空闲优先级任务:

当系统中存在与空闲任务相同优先级的其他任务时,空闲任务会根据配置configIDLE_SHOULD_YIELD 决定是否立即让出CPU。这有助于确保用户任务能够获得及时的CPU时间。

(3)执行空闲任务钩子函数:

如果定义了空闲钩子函数(Idle Hook),那这个函数在每个空闲任务周期都被调用。

(4)低功耗tickless模式:

在空闲周期,FreeRTOS可以停止周期性的系统节拍中断,允许微控制器进入低功耗模式,实现降低功耗。


二、钩子函数

钩子函数这个东西听起来感觉有点奇奇怪怪的,哈哈。为什么要叫钩子呢?

其实简单直白的理解,钩子函数本质就是个回调函数!

这玩意是操作系统中用于满足某些功能而实现的一种机制,基本上所有被freeRTOS调用的钩子函数,都是需要开发者自行实现的。

大部分的钩子函数都在 FreeRTOSConfig.h 这个文件中进行配置裁剪。

当你要用到某个钩子函数功能时,需要先定义钩子函数的并添加你想要实现的逻辑。

比如前面说的空闲任务钩子函数,当启用了vApplicationIdleHook(),就需要在代码中定义该函数:

void vApplicationIdleHook(void) 
{
  // 自己定义钩子函数要实现的操作
}

钩子函数常见的有哪些种类?

FreeRTOS提供了很多的钩子函数,每种钩子函数都有其特定的使用条件和目的。常见的钩子函数及其使用条件如下:

(1)空闲任务钩子函数:

前面解释过空闲任务的作用了,要想使用空闲任务钩子函数,配置方式如下:

1)在FreeRTOSConfig.h 中将 configUSE_IDLE_HOOK 设置为1
2)自行实现 void vApplicationIdleHook()函数


(2)Tick钩子函数

Tick钩子函数在每个Tick中断发生时被调用,属于周期性出发的,一般用于更新系统时间和检查任务延迟列表。配置方式如下:

1)在FreeRTOSConfig.h中将configUSE_TICK_HOOK设置为1
2)并实现void vApplicationTickHook()函数

Tick钩子函数由于是在系统时钟节拍中断中调用的,系统节拍都是由硬件定时器提供的,所以它的周期时间比较精确。一般用于对时间精度要求比较高的操作。

比如:

1)定期触发ADC采样,生成PWM信号,定时电平翻转等。

2)统计 CPU 使用率、任务执行时间等,可以记录 Tick 计数,计算任务运行时间占比。

3)定期检查任务堆栈、内存信息、任务状态等。


(3)栈溢出钩子函数

这个钩子函数比较实用,如果任务的栈溢出了就会被调用到,能及时知晓栈溢出。

要使用这个栈溢出钩子函数,需要配置:

1)在FreeRTOSConfig.h中将configCHECK_FOR_STACK_OVERFLOW设置为1或2
2)实现void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName)函数


(4)守护任务钩子函数

这个钩子函数在守护任务(如Timer服务)启动时被调用。

这个钩子函数常见的应用:

1)在守护任务运行前执行初始化代码(比如初始化外设、配置硬件资源等)。

2)监控或调试守护任务的启动过程。

3)动态调整守护任务的优先级或栈大小。

使用这个钩子函数的配置:

1)在FreeRTOSConfig.h中将configUSE_DAEMON_TASK_STARTUP_HOOK和configUSE_TIMER都设置为1
2)实现void vApplicationDaemonTaskStartupHook()函数


(5)任务创建/删除钩子函数

这个钩子函数在创建任务或者删除任务时被触发。

这个其实很有用处,特别是在代码中需要动态创建/删除任务时就很有用,可以用来监控任务创建/删除是否成功,可以在操作失败时做相应的措施,确保系统的稳定性。

任务创建钩子函数的配置:

1)在FreeRTOSConfig.h中定义configUSE_APPLICATION_TASK_TAG为1(需注意:这个函数在不同的freeRTOS版本中可能不同)
2)注册钩子函数 vApplicationTaskCreateHook( )

任务删除钩子函数配置:

1)在FreeRTOSConfig.h中定义configUSE_TASK_HOOKS为1(需注意:这个函数在不同的freeRTOS版本中可能不同)
2)注册钩子函数 vApplicationTaskDeleteHook( )

注意注意:

注意

  • 钩子函数是在内核上下文中调用的,使用时必须简洁,不能阻塞。尤其是在删除钩子函数中,不能调用可能导致任务阻塞的函数(如延迟函数),毕竟该任务即将被删除掉了。
  • 钩子函数常见用于调试、资源监控、资源跟踪等用途,如果不用它们,可以不用实现的,最好通过配置宏禁用。
  • 确保在实现钩子函数时,函数名和原型完全匹配,避免出现链接错误。毕竟查找bug也是很累人的哦!


控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言