FreeRTOS_时间管理

笔记内容参考(正点原子的FreeRTOS开发手册、cortex-m3权威指南、Cortex-M3和Cortex-M4权威指南等)以及网络笔记

代码环境:CubeMX生成的FreeRTOS



大纲

FreeRTOS时间管理部分,主要是涉及系统节拍以及任务延时管理。

  1. 系统节拍:嵌入式实时操作系统运行,必须要有时钟节拍,就像人的心脏一样。FreeRTOS的时钟节拍通常由SysTick提供,
  2. 任务延时管理:主要是两个延时函数(相对延时函数vTaskDelay,绝对延时函数vTaskDelayUntil)

1、SysTick

SysTick直属与 Coretx-M 内核,它不是 STM32 专属的,只要是 Cortex-M 内核的 MCU 就都有 SysTick。SysTick 定时器是个 24 位的向下计数器,这个计数器的使命就是为系统提供服务的操作系统都需要一个系统时钟,每个系统时钟周期都会触发 OS 内核执行一些系统调用,比如进行任务管理、任务切换等。SysTick 就可以完成此功能,使能 SysTick 中断,设置好定时周期,SysTikc 就会周期性的触发中断,跟系统有关的操作就可以在 SysTick 的中断服务函数中完成。如果不使用系统的话 SysTick 也可以当作普通的定时器使用,完成简单的计时功能SysTick 定时器被捆绑在 NVIC 中,用于产生 SysTick 异常(异常号:15)

  • 在CubeMX中与一个选项就是Timebase source,这里原本默认就是SysTick,那为什么要改为其他的定时器呢?
    因为操作系统需要一个时基,而在我是用的Cortex-M中专门有一个系统时钟SysTick为OS准备。由于FreeRTOS已经使用了SysTick,所以HAL库需要重新弄一个定时器(HAL_Delay())
    在这里插入图片描述

在这里插入图片描述
在文件 core_cm4.h 中用结构体 SysTick_Type 来描述这四个寄存器,结构体 SysTick_Type的定义如下:

#define SCS_BASE (0xE000E000UL)
#define SysTick_BASE (SCS_BASE + 0x0010UL)
typedef struct
{
__IOM uint32_t CTRL; //控制与状态寄存器
__IOM uint32_t LOAD; //自动重装载值寄存器
__IOM uint32_t VAL; //当前计数值寄存器
__IM uint32_t CALIB; //校准值寄存器
} SysTick_Type;
#define SysTick ((SysTick_Type *) SysTick_BASE)

实际使用中操作最多的是 CTRL、LOAD 和 VAL 这三个寄存器,CALIB 寄存器基本不会使用了。CTRL、LOAD 和 VAL 这三个寄存器各 bit 的描述如表 所示:

在这里插入图片描述

  • CTRL寄存器的第二位设置SysTick时钟源,1为内核时钟,一般使用1,也就是系统的主频(如下图)
    在这里插入图片描述

关于SysTick的设置[main.c --> osKernelStart() --> vTaskStartScheduler() --> xPortStartScheduler() --> vPortSetupTimerInterrupt() ]

/*
 * Setup the SysTick timer to generate the tick interrupts at the required
 * frequency.
 */
#if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )

	__weak void vPortSetupTimerInterrupt( void )
	{
		/* Calculate the constants required to configure the tick interrupt. */
		#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 /* configUSE_TICKLESS_IDLE */

		/* Stop and clear the SysTick. */
		portNVIC_SYSTICK_CTRL_REG = 0UL;
		portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;

		/* Configure SysTick to interrupt at the requested rate. */
		portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
		portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
	}
#define portNVIC_SYSTICK_CTRL_REG			( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG			( * ( ( volatile uint32_t * ) 0xe000e014 ) )
  • portNVIC_SYSTICK_CTRL_REG设置SysTick参数:
  • portNVIC_SYSTICK_CLK_BIT:使用内核时钟 168MHz
  • portNVIC_SYSTICK_INT_BIT:打开SysTick中断
  • portNVIC_SYSTICK_ENABLE_BIT:使能SysTick
  • portNVIC_SYSTICK_LOAD_REG设置SysTick重装载值:
  • configSYSTICK_CLOCK_HZ:这个值最终的定义是uint32_t SystemCoreClock = 16000000;这里的16000000是初始值,并不是最终值,因为我们已经选择了内核时钟作为RTC时钟源(168M),在系统初始化运行会进行修改。如下面的代码所示
  • configTICK_RATE_HZ为100,则系统节拍时钟周期为10ms,设置宏configTICK_RATE_HZ为1000,则系统节拍时钟周期为1ms,太频繁的 Tick 中断会导致过频繁的上下文切换,增加系统负担,过于长的上下文切换,会导致任务响应不及时;

在main函数里面引用了 SystemClock_Config(); 然后通过HAL_RCC_ClockConfig,更新了SystemCoreClock值

//代码其他都是删过得

  /* Configure the system clock */
  SystemClock_Config();

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
}

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)
{
  /* Update the SystemCoreClock global variable */
  SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE)>> RCC_CFGR_HPRE_Pos];
}

2、时间相关函数

FreeRTOS 中的时间延迟函数主要有以下两个作用:

  1. 为周期性执行的任务提供延迟。
  2. 对于抢占式调度器,让高优先级任务可以通过时间延迟函数释放 CPU 使用权,从而让低优先级任务可以得到执行。
函数描述
相对延时函数vTaskDelay()
绝对延时函数vTaskDelayUntil()
GET系统节拍xTaskGetTickCount()
GET系统节拍(中断里面使用)xTaskGetTickCountFromISR()

2.1、xTaskGetTickCount

函数原型描述
TickType_t xTaskGetTickCount( void )获取系统当前运行的时钟节拍数。
TickType_t xTaskGetTickCount( void )
{
TickType_t xTicks;

	/* Critical section required if running on a 16 bit processor. */
	portTICK_TYPE_ENTER_CRITICAL();
	{
		xTicks = xTickCount;
	}
	portTICK_TYPE_EXIT_CRITICAL();

	return xTicks;
}

2.2、xTaskGetTickCountFromISR

函数原型描述
TickType_t xTaskGetTickCountFromISR( void )获取系统当前运行的时钟节拍数。(用于在中断服务程序)

TickType_t xTaskGetTickCountFromISR( void )
{
TickType_t xReturn;
UBaseType_t uxSavedInterruptStatus;

	/* RTOS ports that support interrupt nesting have the concept of a maximum
	system call (or maximum API call) interrupt priority.  Interrupts that are
	above the maximum system call priority are kept permanently enabled, even
	when the RTOS kernel is in a critical section, but cannot make any calls to
	FreeRTOS API functions.  If configASSERT() is defined in FreeRTOSConfig.h
	then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
	failure if a FreeRTOS API function is called from an interrupt that has been
	assigned a priority above the configured maximum system call priority.
	Only FreeRTOS functions that end in FromISR can be called from interrupts
	that have been assigned a priority at or (logically) below the maximum
	system call	interrupt priority.  FreeRTOS maintains a separate interrupt
	safe API to ensure interrupt entry is as fast and as simple as possible.
	More information (albeit Cortex-M specific) is provided on the following
	link: https://www.freertos.org/RTOS-Cortex-M3-M4.html */
	portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

	uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR();
	{
		xReturn = xTickCount;
	}
	portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

	return xReturn;
}

2.3、vTaskDelay与vTaskDelayUntil

  • 相对延时是指每次延时都是从任务执行函数vTaskDelay()开始,延时指定的时间结束
  • 绝对延时是指调用vTaskDelayUntil()的任务每隔x时间运行一次。也就是任务周期运行。

在这里插入图片描述
vTaskDelayUntil使用:

static void vTaskLED(void *pvParameters)
{
    TickType_t xLastWakeTime;
    const TickType_t xFrequency = 200;

    /* 获取当前的系统时间 */
    xLastWakeTime = xTaskGetTickCount();
    
    while(1)
    {
        bsp_LedToggle(2);
        
        /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
        vTaskDelayUntil(&xLastWakeTime, xFrequency);
    }
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: FreeRTOS V2 是一个实时操作系统(RTOS),V2 API 是它的应用程序编程接口。 FreeRTOS 是一个广泛应用于嵌入式系统的开源实时操作系统。它提供了可靠的任务调度、时间管理、内存管理和通信机制,使开发者能够轻松地编写出高效、可靠的嵌入式应用程序。 V2 API 是 FreeRTOS 的应用程序编程接口的第二个版本。它提供了一组函数和数据结构,用于控制和管理 FreeRTOS 内核的各个部分。通过这些 API,开发者可以创建和管理任务、队列、信号量、互斥锁等系统资源,实现任务间的通信和同步。 V2 API 在原有的 API 基础上进行了一些增强和改进。它增加了更多的功能和特性,提供了更丰富的资源管理和任务调度机制,提高了系统的可靠性和效率。 使用 FreeRTOS V2 API,开发者可以轻松地编写出符合实时要求的嵌入式应用程序。他们可以通过创建任务和使用任务通信机制,实现系统中不同任务之间的并发执行和数据传输。他们还可以使用 V2 API 中提供的事件标志和定时器功能,实现任务的同步和定时控制。 总之,FreeRTOS V2 API 是 FreeRTOS 实时操作系统的应用程序编程接口的第二个版本。它提供了一种方便、高效的方式来使用 FreeRTOS 的功能和特性,使开发者能够轻松地开发出符合实时要求的嵌入式应用程序。 ### 回答2: FreeRTOS是一个开源的实时操作系统内核,是由迈克尔·贝瑞(Michael Barry)创建的。它提供了一个可移植的、可扩展的、可定制的操作系统内核,用于嵌入式系统和实时应用。其中,FreeRTOS V2是FreeRTOS的第二个主要版本。 FreeRTOS V2提供了一些新的API接口和功能,以增强原有版本的功能和性能。它引入了动态任务优先级分配、任务通知和DMA支持,并对进行多核操作和IPC(进程间通信)做出了改进。同时,FreeRTOS V2添加了一些通用的编程接口,以提供更多的灵活性和互操作性。 在FreeRTOS V2中,新增的任务通知机制使得任务之间可以更加方便地进行通信和同步。它允许任务发送信号给其他任务,以通知其有任务需要处理。这个机制在实时系统中非常有用,可以提高系统的响应性和效率。 此外,FreeRTOS V2还引入了DMA支持,可以通过DMA传输数据,从而减少CPU的负担,提高系统的效率和响应速度。 另外的改进包括使用动态任务优先级分配,可以根据不同任务的优先级动态地分配系统资源,使得系统更加灵活。 总之,FreeRTOS V2作为FreeRTOS的新版本,通过新增API接口和功能的方式,进一步提升了它的功能和性能,使得嵌入式系统和实时应用能够更加高效地运行。 ### 回答3: FreeRTOS是一个开源的即时操作系统内核,提供轻量级的任务调度和资源管理功能,针对嵌入式系统设计开发。目前最新版本是FreeRTOS V10.4.1。 FreeRTOS V2 API是FreeRTOS内核的一种编程接口,用于实现任务的创建、删除、挂起和恢复等操作。V2 API是在旧版本API基础上进行了优化和扩展,提供了更强大和灵活的功能。 V2 API引入了任务通知功能,可以在任务之间进行通信和同步操作。通过信号量和消息队列等机制,任务可以共享和传递数据。这大大简化了任务之间的协作和数据交换。 V2 API还增加了事件组功能,可以用于等待和通知多个事件的发生。任务可以根据不同的事件发生状态执行不同的操作。这在多任务并发和同步控制方面非常有用。 另外,V2 API还提供了软件定时器功能,可以用于定期执行一些操作。这对于周期性任务和定时操作非常有帮助。 总之,FreeRTOS V2 API拓展了旧版本API的功能,提供了更多的任务管理和同步机制,使得嵌入式系统开发更加灵活和方便。它广泛应用于各种类型的嵌入式系统,并受到开发者的广泛欢迎。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值