FreeRTOS操作系统——空闲任务及钩子函数(二十)

FreeRTOS操作系统学习

文章目录

  • FreeRTOS操作系统学习
  • 前言
  • 一、空闲任务
    • 1、空闲任务创建
    • 2、空闲任务函数
  • 二、空闲任务钩子函数
    • 1、空闲任务钩子函数简介
    • 2、空闲任务钩子函数实验
  • 总结

前言

处理器总是需要代码来执行——所以至少要有一个任务处于运行态,那么这个任务就是空闲任务,空闲任务拥有最低优先级(优先级 0)

一、空闲任务

当 FreeRTOS 的调度器启动以后就会自动的创建一个空闲任务,这样就可以确保至少有一任务可以运行。但是这个空闲任务使用最低优先级,如果应用中有其他高优先级任务处于就绪态的话这个空闲任务就不会跟高优先级的任务抢占 CPU 资源。

1、空闲任务创建

当调用函数 vTaskStartScheduler()启动任务调度器的时候此函数就会自动创建空闲任务

2、空闲任务函数

空闲任务的任务函数为 prvIdleTask(),但是实际上是找不到这个函数的,因为它是通过宏定义来实现的

空闲任务执行过程:
1、释放内存
2、检查是否使用抢占内核,如果没使用就调用taskYIELD
3、如果使用抢占式内核,而且configIDLE_SHOULD_YIELD等于1,那么空闲任务就把CPU使用权让给同优先级的其他任务。
4、是否使能钩子函数,使能的话就调用
5、是否使能Tickless模式,使能的话就做相应的处理

二、空闲任务钩子函数

1、空闲任务钩子函数简介

FreeRTOS 中有多个钩子函数,钩子函数类似回调函数,当某个功能(函数)执行的时候就会调用钩子函数,至于钩子函数的具体内容那就由用户来编写。如果不需要使用钩子函数的话就什么也不用管,钩子函数是一个可选功能,可以通过宏定义来选择使用哪个钩子函数
FreeRTOS操作系统——空闲任务及钩子函数(二十)_第1张图片空闲任务钩子函数会被空闲任务每循环一次就自动调用一次。
通常空闲任务钩子函数被用于:
1、 执行低优先级,后台或需要不停处理的功能代码。
2、 测试出系统处理裕量(空闲任务只会在所有其它任务都不运行时才有机会执行,所以测量出空闲任务占用的处理时间就可以清楚的知道系统有多少富余的处理时间)。
3、将处理器配置到低功耗模式——提供一种自动省电方法,使得在没有任何应用功能
需要处理的时候,系统自动进入省电模式。

空闲任务钩子函数必须遵从以下规则:
1、绝不能阻塞或挂起。空闲任务只会在其它任务都不运行时才会被执行(除非有应用任务共享空闲任务优先级)。以任何方式阻塞空闲任务都可能导致没有任务能够进入运行态!
2、如果应用程序用到了 vTaskDelete() API 函数,则空闲钩子函数必须能够尽快返回。因为在任务被删除后,空闲任务负责回收内核资源。如果空闲任务一直运行在钩子函数中,则无法进行回收工作。

创建一个与空闲任务优先级相同的任务。
创建一个任务是最好的解决方法,但是这种方法会消耗更多的 RAM。
要使用空闲任务钩子函数首先要在 FreeRTOSConfig.h 中将宏 configUSE_IDLE_HOOK 改 为 1,然后编写空闲任务钩子函数 vApplicationIdleHook()。通常在空闲任务钩子函数中将处理器设置为低功耗模式来节省电能。这种低功耗的实现方法称之为通用低功耗模式。

2、空闲任务钩子函数实验

如何在 FreeRTOS 空闲任务钩子函数中实现低功耗。

FreeRTOS操作系统——空闲任务及钩子函数(二十)_第2张图片
FreeRTOS操作系统——空闲任务及钩子函数(二十)_第3张图片

//进入低功耗模式前需要处理的事情
void BeforeEnterSleep(void)
{
//关闭某些低功耗模式下不使用的外设时钟,此处只是演示性代码
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,DISABLE);
}
//退出低功耗模式以后需要处理的事情
void AfterExitSleep(void)
{
//退出低功耗模式以后打开那些被关闭的外设时钟,此处只是演示性代码
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE); 
}
//空闲任务钩子函数
void vApplicationIdleHook(void)
{
__disable_irq();
__dsb(portSY_FULL_READ_WRITE );
__isb(portSY_FULL_READ_WRITE );
BeforeEnterSleep(); //进入低功耗模式之前需要处理的事情
__wfi(); //进入低功耗模式
AfterExitSleep(); //退出低功耗模式之后需要处理的事情
__dsb(portSY_FULL_READ_WRITE );
__isb(portSY_FULL_READ_WRITE );
__enable_irq();
}

首先调用__disable_irq()函数关闭系统中断请求,然后调用PreSleepProcessing()做进入睡眠模式前的一些低功耗处理,这里仅关闭了GPIO的时钟,接着调用__wfi()进入WFI低功耗模式,当调用PostSleepProcessing()的时候说明已经退出低功耗模式了,然后恢复外设时钟,调用__enable_irq();开启中断请求

总结

空闲任务钩子函数主要目的就是调用 WFI 指令使 STM32F103 进入睡眠模式,在进入和退出低功耗模式的时候也可以做一些其他处理,比如关闭外设时钟等等,用法和Tickless 模式类似。

你可能感兴趣的:(单片机,嵌入式硬件)