FreeRTOS系列学习笔记九-->时间管理

FreeRTOS系列学习笔记九–>时间管理


前言

在前面的章节实验例程中,频繁地使用了 FreeRTOS 提供的延时函数,使用延时函数会使得任务进入阻塞态,直至延时完成,任务才会重新进入就绪态。FreeRTOS 是如何对延时任务进行阻塞的,又是如何判断任务延时超时的,这些都是属于 FreeRTOS 时间管理的相关内容。

一、FreeRTOS 系统时钟节拍

1:FreeRTOS系统时钟节拍简介

任务的操作系统都需要时钟节拍,FreeRTOS 也不例外。FreeRTOS 有一个系统时钟节拍计数器——xTickCount,xTickCount 是一个全局变量,在 tasks.c 文件中有定义,具体的定义代码如下所示:

/*如果configINITIAL_TICK_COUNT没有被而外定义,那么将它定义为0*/
#ifndef configINITIAL_TICK_COUNT
    #define configINITIAL_TICK_COUNT    0

PRIVILEGED_DATA static volatile TickType_t xTickCount =( TickType_t ) configINITIAL_TICK_COUNT;

从 上 面 的 代 码 可 以 看 到 , xTickCount 在 定 义 时 , 被 赋 了 初 值 , 初 值 由 宏 定 义configINITIAL_TICK_COUNT 定义,在通常情况下系统使用节拍计数器的初值都是设置为 0,除非在个别特殊使用场合,初值是可以由使用者手动配置的。

2:FreeRTOS 系统时钟节拍来源

FreeRTOS 的系统时钟节拍计数器为全局变量 xTickCount,那么 FreeRTOS 又是何时操作这个系统时钟节拍计数器的呢?
一般情况而言我们可以通过SysTick 的中断服务函数中去操作这个全局变量xTickCount,但是我们也可以通过其他硬件定时器来提供时钟节拍,这里我采用了SysTick 的中断服务函数来处理时钟节拍。
在FreeRTOS 启动任务调度器的过程中会对 SysTick 进行初始化,会覆盖掉系统配置的SysTick初始化,因此最终 SysTick 的配置为 FreeRTOS 对 SysTick 的配置。

有些板子的SysTick的时钟源频率与 CPU 时钟频率不一致,而为了让SysTick 的时钟源频率与 CPU 的时钟源频率相同来正常的使用相关的函数定义,我们会自己定义一个宏来适配:configSYSTICK_CLOCK_HZ

/* 定义 SysTick 时钟频率,
* 当 SysTick 时钟频率与内核时钟频率不同时才可以定义,
* 单位: Hz, 默认: 不定义
*/
#define configSYSTICK_CLOCK_HZ (configCPU_CLOCK_HZ / 8)

而想知道FreeRTOS 启动任务调度器的过程中会对 SysTick 进行初始化,可以在任务切换那个章节中看到xPortStartScheduler()会对 SysTick进行配置。

/*在xPortStartScheduler()函数中截取的有关对SysTick 配置的关键代码*/
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;		/*第一行代码用于设置 SysTick 的中断优先级为最低优先等级*/
vPortSetupTimerInterrupt();						/*调用函数vPortSetupTimerInterrupt()对 SysTick 进行配置*/

接下来介绍函数vPortSetupTimerInterrupt()的具体代码:

__weak void vPortSetupTimerInterrupt( void )
{
   
 /* 此宏为低功耗的相关配置,无需理会 */
 #if ( configUSE_TICKLESS_IDLE == 1 )
 {
   
 ulTimerCountsForOneTick = (configSYSTICK_CLOCK_HZ /
 configTICK_RATE_HZ);
 xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER /
 ulTimerCountsForOneTick;
 ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR /
 (configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ);
 }
 #endif
 
 /* 清空 SysTick 控制状态寄存器 */
 portNVIC_SYSTICK_CTRL_REG = 0UL;
 /* 清空 SysTick 当前数值寄存器 */
 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
 
 /* 根据配置的系统时钟节拍频率,
 * 设置 SysTick 重装载寄存器
 */
 portNVIC_SYSTICK_LOAD_REG =
 (configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ) - 1UL;
 /* 设置 SysTick 控制状态寄存器,
 * 设置 SysTick 时钟源不分频(与 CPU 时钟源同频率)、
 * 开启 SysTick 计数清零中断(SysTick 为向下计数)、
 * 开启 SysTick 计数
 */
 portNVIC_SYSTICK_CTRL_REG = (portNVIC_SYSTICK_CLK_BIT |
 							  portNVIC_SYSTICK_INT_BIT |
 						      portNVIC_SYSTICK_ENABLE_BIT);
}

3:FreeRTOS 系统时钟节拍处理

了解完在FreeRTOS 系统中系统时钟节拍的来源后,我们来看看他是怎么对时钟节拍进行处理的。
在上面的配置中我们设置了FreeRTOS 的系统时钟节拍来自 SysTick,那么FreeRTOS 系统时钟节拍的处理,自然就是在 SysTick 的中断服务函数中完成的。在HAL库生成的代码中SysTick 的中断服务函数被定义stm32f1xx_it.c文件中。
具体代码如下:

void SysTick_Handler(void)
{
   
  /* USER CODE BEGIN SysTick_IRQn 0 */
		HAL_IncTick();
	
	         /* OS 开始跑了,才执行正常的调度处理 */
	 if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
	 {
   
			xPortSysTickHandler();
	 }
 
  /* USER CODE END SysTick_IRQn 0 */

  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

从上面的代码可以看出,在 SysTick 的中断服务函数中,除了调用函数 HAL_IncTick()外,还通过函数xTaskGetSchedulerState()判断任务调度器是否运行,如果任务调度器运行,那么就调用函数 xPortSysTickHandler()处理 FreeRTOS 的时钟节拍。

让我们来看看xPortSysTickHandler()的具体函数定义:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值