FREERTOS学习笔记,软件定时器管理

绪论

软件定时器用于以后的固定时间,或以一个固定频率周期运行的函数。通过软件定时器执行的函数称为软件定时器的回调函数。软件定时器通过FREERTOS内核实施与控制,它并不需要硬件支持,与底层硬件定时器无关。
软件定时器函数是可选的,使用软件定时器需要以下操作:
1,编译源文件中的FreeRTOS/Source/timers.c 。
2,将FreeRTOSConfig.h中的 configUSE_TIMERS设置为1。

软件定时器回调函数

函数原型如下:

void ATimerCallback( TimerHandle_t xTimer );

软件定时器回调函数从头执行到尾,属于正常执行模式,执行时间应尽可能短,并不可以进入阻塞模式。

软件定时器的属性特征

1,软件定时器的周期
在两个软件定时器回调函数开始执行的之间的时间。
2,一次性与重装载软件定时器
一次性定时器:只会执行一次软件定时器回调函数,不能自己重新启动,只能用户再启动。
自动重载定时器:一旦启动,自动重载定时器将会周期性自动重新启动。从而周期性执行软件定时器回调函数。

3,软件定时器状态
休眠
执行
其图示如下:
FREERTOS学习笔记,软件定时器管理_第1张图片
FREERTOS学习笔记,软件定时器管理_第2张图片

RTOS定时器服务任务

所有的定时器回调函数均在同一个软件定时器服务任务中调用。定时器服务任务在进程调度器开始执行时自动创建而成,它的优先级以及堆栈大小通过FreeRTOSConfig.h中的configTIMER_TASK_PRIORITY和configTIMER_TASK_STACK_DEPTH来定义。

软件定时器指令队列

定时器指令队列是一个标准FREERTOS队列,并在任务调度器开始时自动创建,该队列的长度通过FreeRTOSConfig.h中的configTIMER_QUEUE_LENGTH来定义。

运行的大致原理如下所示:
FREERTOS学习笔记,软件定时器管理_第3张图片
定时器服务任务类似于一般任务受任务调度器调度。当他的优先级足够高时,它仅运行进程指令与执行定时器回调函数。

实例

当定时器服务函数优先级低于一般任务时,其过程如下:
FREERTOS学习笔记,软件定时器管理_第4张图片
在t1时,任务一优先级最高,定时器任务处于阻塞状态。
t2时刻,任务一调用xTimerStart(),xTimerStart()发送指令给定时器队列,使得定时器服务函数退出阻塞状态,由于定时器服务函数优先级低于任务一,故定时器服务函数处于ready状态。
t3时刻任务一执行完xTimerStart()函数。依旧处于运行态。
t4任务一进入阻塞状态,此时开始执行定时器服务函数。然后定时器服务函数开始处理队列中命令。

注意:软件定时器开始的时间是从任务发送开启一个定时器到队列的指令时间,而不是定时器服务函数收到开启定时器指令的时间。
t5时刻定时器服务函数处理完指令进入阻塞状态。

当定时器服务任务优先级高于一般任务时,其过程如下所示:
FREERTOS学习笔记,软件定时器管理_第5张图片
t2时刻任务一调用xTimerStart(),从而将指令发送到定时器队列(注意是刚将指令放入到队列,但xTimerStart()还没执行完),此时由于定时器服务任务优先级较高,故会抢占CPU,从而开始指令定时器任务直到执行完进入阻塞状态。

创建与启动软件定时器

xTimerCreate()
该函数用于创建一个软件定时器,可以在任务调度器前执行,也可以在某一任务中执行。其函数原型如下:

TimerHandle_t xTimerCreate( const char * const pcTimerName,
							TickType_t xTimerPeriodInTicks,
							UBaseType_t uxAutoReload,
							void * pvTimerID,
							TimerCallbackFunction_t pxCallbackFunction );

参数:
pcTimerName:定时器名字,方便与调试,内核不需要。
xTimerPeriodInTicks:定时器周期。
uxAutoReload:是否重装载,pdTRUE表重装载,pdFALSE表一次性。
pvTimerID:定时器ID,当一个回调函数被多个定时器使用时,可以用于提供不同存储空间。
pxCallbackFunction :定时器回调函数
返回值:返回NULL表示空间不足以创建,从而创建失败。非空表示创建成功,返回值为创建成的定时器的句柄。

xTimerStart()
该函数用于启动一个处于休眠状态的定时器,或复位一个处于运行状态的定时器。xTimerStop() 被用于停止一个处于运行状态的定时器。
其函数原型如下:

BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );

相关参数:
xTimer:之前创建的定时器的句柄。
xTicksToWait :当使用相关函数时会将指令放到队列中,当队列已满时,该函数就会进入阻塞状态,这个参数就是为了设置进入阻塞态等待的最大时间。
返回值:pdPASS成功,pdFALSE失败

实例

创建两个软件定时器,分别为一次性定时器与周期定时器:

/* The periods assigned to the one-shot and auto-reload timers are 3.333 second and half a
second respectively. */
#define mainONE_SHOT_TIMER_PERIOD pdMS_TO_TICKS( 3333 )
#define mainAUTO_RELOAD_TIMER_PERIOD pdMS_TO_TICKS( 500 )
int main( void )
{
	TimerHandle_t xAutoReloadTimer, xOneShotTimer;
	BaseType_t xTimer1Started, xTimer2Started;
	/* Create the one shot timer, storing the handle to the created timer in xOneShotTimer. */
	xOneShotTimer = xTimerCreate(
					/* Text name for the software timer - not used by FreeRTOS. */
					"OneShot",
					/* The software timer's period in ticks. */
					mainONE_SHOT_TIMER_PERIOD,
					/* Setting uxAutoRealod to pdFALSE creates a one-shot software timer. */
					pdFALSE,
					/* This example does not use the timer id. */
					0,
					/* The callback function to be used by the software timer being created. */
					prvOneShotTimerCallback );
	/* Create the auto-reload timer, storing the handle to the created timer in xAutoReloadTimer. 
	*/
	xAutoReloadTimer = xTimerCreate(
						/* Text name for the software timer - not used by FreeRTOS. */
						"AutoReload",
						/* The software timer's period in ticks. */
						mainAUTO_RELOAD_TIMER_PERIOD,
						/* Setting uxAutoRealod to pdTRUE creates an auto-reload timer. */
						pdTRUE,
						/* This example does not use the timer id. */
						0,
						/* The callback function to be used by the software timer being created. 					
						*/
						prvAutoReloadTimerCallback );
	/* Check the software timers were created. */
	if( ( xOneShotTimer != NULL ) && ( xAutoReloadTimer != NULL ) )
	{
		/* Start the software timers, using a block time of 0 (no block time). The scheduler has
		not been started yet so any block time specified here would be ignored anyway. */
		xTimer1Started = xTimerStart( xOneShotTimer, 0 );
		xTimer2Started = xTimerStart( xAutoReloadTimer, 0 );
		/* The implementation of xTimerStart() uses the timer command queue, and xTimerStart()
		will fail if the timer command queue gets full. The timer service task does not get
		created until the scheduler is started, so all commands sent to the command queue will
		stay in the queue until after the scheduler has been started. Check both calls to
		xTimerStart() passed. */
		if( ( xTimer1Started == pdPASS ) && ( xTimer2Started == pdPASS ) )
		{
			/* Start the scheduler. */
			vTaskStartScheduler();
		}
	}
	/* As always, this line should not be reached. */
	for( ;; );
}

两个定时器回调函数为:

static void prvOneShotTimerCallback( TimerHandle_t xTimer )
{
TickType_t xTimeNow;
/* Obtain the current tick count. */
xTimeNow = xTaskGetTickCount();
/* Output a string to show the time at which the callback was executed. */
vPrintStringAndNumber( "One-shot timer callback executing", xTimeNow );
/* File scope variable. */
ulCallCount++;
}
static void prvAutoReloadTimerCallback( TimerHandle_t xTimer )
{ T
ickType_t xTimeNow;
/* Obtain the current tick count. */
xTimeNow = uxTaskGetTickCount();
/* Output a string to show the time at which the callback was executed. */
vPrintStringAndNumber( "Auto-reload timer callback executing", xTimeNow );
ulCallCount++;
}

运行结果如下所示:
FREERTOS学习笔记,软件定时器管理_第6张图片

定时器ID

每一个软件定时器都有一个ID,这个ID被放在一个void型的指针空间里,所以它可以为整形数据,或者指向其他数据或指向函数。当软件定时器初始化时,一个ID就会分配给该定时器,这个ID可通过vTimerSetTimerID()来更新,也可通过pvTimerGetTimerID()来读取,这两个函数可以直接操作定时器,并不需要放入队列中等待执行。
函数原型如下:

void vTimerSetTimerID( const TimerHandle_t xTimer, void *pvNewID );

参数
xTimer:定时器句柄。
pvNewID :新ID

void *pvTimerGetTimerID( TimerHandle_t xTimer );

返回值即为ID。

实例:将ID用作回调函数参数

创建两个定时器,一个为一次性,另一个为周期性

/* Create the one shot timer software timer, storing the handle in xOneShotTimer. */
xOneShotTimer = xTimerCreate( "OneShot",
							mainONE_SHOT_TIMER_PERIOD,
							pdFALSE,
							/* The timer’s ID is initialized to 0. */
							0,
							/* prvTimerCallback() is used by both timers. */
							prvTimerCallback );


/* Create the auto-reload software timer, storing the handle in xAutoReloadTimer */
xAutoReloadTimer = xTimerCreate( "AutoReload",
							mainAUTO_RELOAD_TIMER_PERIOD,
							pdTRUE,
							/* The timer’s ID is initialized to 0. */
							0,
							/* prvTimerCallback() is used by both timers. */
							prvTimerCallback );

回调函数如下所示:

static void prvTimerCallback( TimerHandle_t xTimer )
{
	TickType_t xTimeNow;
	uint32_t ulExecutionCount;
	/* A count of the number of times this software timer has expired is stored in the timer's
	ID. Obtain the ID, increment it, then save it as the new ID value. The ID is a void
	pointer, so is cast to a uint32_t. */
	ulExecutionCount = ( uint32_t ) pvTimerGetTimerID( xTimer );
	ulExecutionCount++;
	vTimerSetTimerID( xTimer, ( void * ) ulExecutionCount );
	/* Obtain the current tick count. */
	xTimeNow = xTaskGetTickCount();
	/* The handle of the one-shot timer was stored in xOneShotTimer when the timer was created.
	Compare the handle passed into this function with xOneShotTimer to determine if it was the
	one-shot or auto-reload timer that expired, then output a string to show the time at which
	the callback was executed. */
	if( xTimer == xOneShotTimer )
	{
		vPrintStringAndNumber( "One-shot timer callback executing", xTimeNow );
	}
	else
	{
		/* xTimer did not equal xOneShotTimer, so it must have been the auto-reload timer that
		expired. */
		vPrintStringAndNumber( "Auto-reload timer callback executing", xTimeNow );
		if( ulExecutionCount == 5 )
		{
			/* Stop the auto-reload timer after it has executed 5 times. This callback function
			executes in the context of the RTOS daemon task so must not call any functions that
			might place the daemon task into the Blocked state. Therefore a block time of 0 is
			used. */
			xTimerStop( xTimer, 0 );
		}
	}
}

结果如图:
FREERTOS学习笔记,软件定时器管理_第7张图片
由图可以看出ulExecutionCount被作为参数一直传递。

改变定时器周期

xTimerChangePeriod()
函数原型:

BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
						TickType_t xNewTimerPeriodInTicks,
						TickType_t xTicksToWait );

参数:
xTimer:定时器句柄
xNewTimerPeriodInTicks:新的定时器周期
xTicksToWait :若定时器指令队列已满,该函数进入阻塞状态的最大时间
返回值:pdPASS:成功,pdFALSE:失败

复位定时器

xTimerReset()
执行之后,定时器重新开始计数。亦可用于启动一个处于休眠状态的定时器。
函数原型如下:

BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );

参数
xTimer:定时器句柄
xTicksToWait :定时器指令队列已满时,进入阻塞状态最大等待时间
返回值:pdPASS:成功,pdFALSE:失败

你可能感兴趣的:(FREERTOS学习笔记,软件定时器管理)