FreeRTOS学习笔记——精准延时

主机环境:Windows

开发环境:MDK4.7.2

FreeRTOS版本:FreeRTOS8.1.2

目标环境:STM32F030C8T6

FreeRTOS中除掉基本的延时函数以外还有一个精准延时函数vTaskDelayUntil(),它可以实现相较于vTaskDelay()更加精准的延时,一般用于实现一个固定执行周期的需求(当你需要让你的任务以固定频率周期性的执行时),熟悉vTaskDelay()之后,再看vTaskDelayUntil()就容易多了

void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
{
TickType_t xTimeToWake;
BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;

	configASSERT( pxPreviousWakeTime );
	configASSERT( ( xTimeIncrement > 0U ) );
	configASSERT( uxSchedulerSuspended == 0 );

	vTaskSuspendAll();
	{
		/* Minor optimisation.  The tick count cannot change in this
		block. */
		const TickType_t xConstTickCount = xTickCount;

		/* Generate the tick time at which the task wants to wake. */
		xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;

		if( xConstTickCount < *pxPreviousWakeTime )
		{
			/* The tick count has overflowed since this function was
			lasted called.  In this case the only time we should ever
			actually delay is if the wake time has also	overflowed,
			and the wake time is greater than the tick time.  When this
			is the case it is as if neither time had overflowed. */
			if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
			{
				xShouldDelay = pdTRUE;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			/* The tick time has not overflowed.  In this case we will
			delay if either the wake time has overflowed, and/or the
			tick time is less than the wake time. */
			if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
			{
				xShouldDelay = pdTRUE;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		/* Update the wake time ready for the next call. */
		*pxPreviousWakeTime = xTimeToWake;

		if( xShouldDelay != pdFALSE )
		{
			traceTASK_DELAY_UNTIL();

			/* Remove the task from the ready list before adding it to the
			blocked list as the same list item is used for both lists. */
			if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
			{
				/* The current task must be in a ready list, so there is
				no need to check, and the port reset macro can be called
				directly. */
				portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

			prvAddCurrentTaskToDelayedList( xTimeToWake );
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	xAlreadyYielded = xTaskResumeAll();

	/* Force a reschedule if xTaskResumeAll has not already done so, we may
	have put ourselves to sleep. */
	if( xAlreadyYielded == pdFALSE )
	{
		portYIELD_WITHIN_API();
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}
vTaskDelayUntil()之所以能够实现精准延时是因为其维持了一个绝对时间而不是像vTaskDelay()采用相对时间,参数pxPreviousWakeTime只需要第一次调用该函数时赋值,以后每次调用只需要传递该值的地址即可,调度器挂起之后申请了时钟副本xConstTickCount,根据前一次的唤醒时间计算本次的唤醒时间xTimeToWake,如果pxPreviousWakeTime的值大于xConstTickCount即意味着时钟计数器已经溢出了,然后判断本次唤醒时间是否溢出,如果唤醒时间也溢出且在当前时钟之后,则标记xShouldDelay为pdTRUE即该任务应当插入延时链表中,

FreeRTOS学习笔记——精准延时_第1张图片

如果时钟计数器没有溢出的时,xTimeToWake溢出或者没有溢出都需要将该任务插入延时链表中,这里有个疑问,什么情况下该任务是不需要插入延时链表中?即什么时候会出现xTimeToWake唤醒时间是在当前时钟的前面,这里还没搞明白,感觉应该不会出现才对,等想通了再来看吧。处理完毕之后更新pxPreviousWakeTime的值,并根据标记将任务插入延时链表中,最后唤醒调度器,并根据结果查看是否需要强制执行一次任务切换。函数分析也就完毕了。。。


你可能感兴趣的:(FreeRTOS学习笔记——精准延时)