FreeRTOS-钩子函数
目录
钩子函数
Tick滴答钩子
/* FreeRTOSConfig.h */ #define configUSE_TICK_HOOK 1 /* cmsis_os2.h */ /** Dummy implementation of the callback function vApplicationTickHook(). */ #if (configUSE_TICK_HOOK == 1) __WEAK void vApplicationTickHook (void){} #endif
vApplicationTickHook()函数在中断服务程序中执行,所以这个函数必须短而有效率,不能加延时,不能大量使用堆栈,也不能调用“FromISR”结尾的API函数。
vApplicationTickHook()函数的运行周期由configTICK_RATE_HZ决定,一般都设置为1ms。
/* FreeRTOSConfig.h */ #define configTICK_RATE_HZ ((TickType_t)1000)
T = 1/f = 1/1000 = 0.001s = 1ms。?
空闲钩子
/* FreeRTOSConfig.h */ #define configUSE_IDLE_HOOK 1 /* cmsis_os2.h */ /** Dummy implementation of the callback function vApplicationIdleHook(). */ #if (configUSE_IDLE_HOOK == 1) __WEAK void vApplicationIdleHook (void){} #endif
运行周期:没有其它任务时,一直被调用,调用周期非常短。
如果没有其它任务优先级和空闲任务相同,那空闲任务钩子函数里不能阻塞或挂起自身。因为FreeRTOS任何时候都需要有一个任务在运行,否则可能会造成没有任务能够进入运行态。
如果其它任务占用的实际比较少,空闲钩子函数将占用大量的系统时间片资源,则用户可以将一些功能(对时序无要求)在该函数内实现。
栈溢出钩子
/* FreeRTOSConfig.h */ #define configCHECK_FOR_STACK_OVERFLOW 1 // 或 #define configCHECK_FOR_STACK_OVERFLOW 2 /** Dummy implementation of the callback function vApplicationStackOverflowHook(). */ #if (configCHECK_FOR_STACK_OVERFLOW > 0) __WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, signed char *pcTaskName) { (void)xTask; (void)pcTaskName; } #endif
运行周期:任务栈溢出时
并非所有栈溢出都会触发栈溢出钩子函数。栈溢出可能会把系统栈溢出检测代码的数据也给破坏掉了,而导致栈溢出检测失效,这时栈溢出钩子函数也就无法调用了。
参数可以知道哪个任务的栈溢出。
守护进程钩子
/* FreeRTOSConfig.h */
#define configUSE_DAEMON_TASK_STARTUP_HOOK 1
#define configUSE_TIMER 1 // 钩子函数需要Timer任务下实现
/* cmsis_os2.h */
/**
Dummy implementation of the callback function vApplicationDaemonTaskStartupHook().
*/
#if (configUSE_DAEMON_TASK_STARTUP_HOOK == 1)
__WEAK void vApplicationDaemonTaskStartupHook (void){}
#endif
钩子应用场景:获取CPU占用率
可以统计在一定周期时间内系统执行空闲任务的tick数,就可以获取到CPU空闲率(如1s内空闲任务运行了0.9s,则CPU占用率为10%)。
utils_cpu.h文件
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __UTILS_CPU_H
#define __UTILS_CPU_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#define CALCULATION_PERIOD 1000
/* Exported functions prototypes ---------------------------------------------*/
uint16_t osGetCPUUsage (void);
/* Private defines -----------------------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
utils_cpu.c文件
/* Includes ------------------------------------------------------------------*/
#include "utils_cpu.h"
#include "main.h"
#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */
/* Private includes ----------------------------------------------------------*/
#include "FreeRTOS.h" // ARM.FreeRTOS::RTOS:Core
#include "task.h" // ARM.FreeRTOS::RTOS:Core
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
xTaskHandle xIdleHandle = NULL;
__IO uint32_t osCPU_Usage = 0;
uint32_t osCPU_IdleStartTime = 0;
uint32_t osCPU_IdleSpentTime = 0;
uint32_t osCPU_TotalIdleTime = 0;
/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/**
* @brief Application Idle Hook
* @param None
* @retval None
*/
void vApplicationIdleHook(void)
{
if( xIdleHandle == NULL )
{
/* Store the handle to the idle task. */
xIdleHandle = xTaskGetCurrentTaskHandle();
}
}
/**
* @brief Application Idle Hook
* @param None
* @retval None
*/
void vApplicationTickHook (void)
{
static int tick = 0;
if(tick ++ > CALCULATION_PERIOD)
{
tick = 0;
if(osCPU_TotalIdleTime > 1000)
{
osCPU_TotalIdleTime = 1000;
}
osCPU_Usage = (100 - (osCPU_TotalIdleTime * 100) / CALCULATION_PERIOD);
osCPU_TotalIdleTime = 0;
}
}
/**
* @brief Start Idle monitor
* @param None
* @retval None
*/
void StartIdleMonitor (void)
{
if( xTaskGetCurrentTaskHandle() == xIdleHandle )
{
osCPU_IdleStartTime = xTaskGetTickCountFromISR();
}
}
/**
* @brief Stop Idle monitor
* @param None
* @retval None
*/
void EndIdleMonitor (void)
{
if( xTaskGetCurrentTaskHandle() == xIdleHandle )
{
/* Store the handle to the idle task. */
osCPU_IdleSpentTime = xTaskGetTickCountFromISR() - osCPU_IdleStartTime;
osCPU_TotalIdleTime += osCPU_IdleSpentTime;
}
}
/**
* @brief Stop Idle monitor
* @param None
* @retval None
*/
uint16_t osGetCPUUsage (void)
{
return (uint16_t)osCPU_Usage;
}
FreeRTOSConfig.h配置文件部分内容
/* FreeRTOSConfig.h */
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#define traceTASK_SWITCHED_IN() extern void StartIdleMonitor(void); \
StartIdleMonitor()
#define traceTASK_SWITCHED_OUT() extern void EndIdleMonitor(void); \
EndIdleMonitor()
实现原理
在第一次进入空闲钩子函数时获取空闲任务的句柄到xIdleHandle,之后进入该钩子函数时忽略操作。
Tick滴答钩子函数运行周期由configTICK_RATE_HZ决定,假设设置为1ms。则每秒进一次Tick滴答钩子函数的条件判断。????????
traceTASK_SWITCHED_IN()函数是每次切入到一个任务时执行,traceTASK_SWITCHED_OUT()函数是每次从一个任务中切出时执行。所以通过判断当前是不是空闲任务的进入和退出,并记录空闲任务的开始和结束时间。
traceTASK_SWITCHED_IN()函数中获取时间计数器值,traceTASK_SWITCHED_OUT()函数中获取空闲任务一次进入和退出的计数差值,即运行一次空闲任务的计数值,并进行累加。累加值在Tick滴答钩子函数中有使用到。每秒都会进一次Tick滴答钩子函数的条件判断,每次清零累加值。累加值最大1000,CPU占用率 = 1 - 空闲计数 / 1000,1000为1s计数值。代码中osCPU_Usage为CPU占用率(去掉%)。?
获取内存
获取空闲内存:xPortGetFreeHeapSize(),返回size_t(uint32_t)类型,单位为字节。
获取总内存:configTOTAL_HEAP_SIZE。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!