单片机,FreeRtos操作系统软件定时器(Software Timer)原理及其应用!!!

         前言:本文参考,韦东山开发文档,连接放在最后

基本概念理解

        软件定时器(Software Timer),类似于闹钟,当规定的时间到来时,提醒你,去完成某件事情,闹钟提醒我们的事情,可以是每天重复性的任务,也可以是只执行一次的任务。将功能带入到软件定时器,得到定义,软件定时器(Software Timer)是一个定时机制,允许任务或函数在特定时间间隔后被执行。软件定时器的核心功能是延时和周期性执行任务。

        需要注意的是,软件定时器(Software Timer)是依靠FreeRtos操作系统的,系统滴答中断(Tick Interrupt)来运行的,这里系统滴答中断提供的是软件定时器(Software Timer)判断时间的标准。

        同样的软件定时器(Software Timer)因为功能不同也被分为 一次性定时器 和周期性定时器概念如下所示。

        一次性定时器:当达到设定时间时触发一次并停止

        周期性定时器:当达到设定时间周期间隔,就会重复触发,知道手动停止定时器

        在概念中最重要的一点是,因为FreeRtos是操作系统(RTOS),要求任务的并发性,并发性也就是任务的同时执行是通过中断函数来切换的,这里也就是通过系统滴答中断(Tick Interrupt)的中断函数来切换的,这个函数中不能放入执行时间不确定的程序,回影响系统切换任务,也就是影响并发性,因此,软件定时器(Software Timer)的执行函数会系统内核中调用函数,通过函数来读写 RTOS command queue 在系统内核中通过去读队列的数值,来在普通任务上下文调用不同的函数, RTOS守护 任务(RTOS Damemon Task)在普通任务的上下文执行,从而避免在中断中执行时间不确定的操作。

        RTOS守护 任务(RTOS Damemon Task)的调度和普通任务的调度,没有什么区别,同样需要遵守任务的优先级规则。这里需要注意的是,软件定时器在创建过后,并不会启动,需要调用函数来启动软件定时器。

        如果软件定时器在创建之后,没用使用函数调用,这个时候本身的状态是 冬眠(Dormant) 状态,是不能够正常相应的。

函数原型

      软件定时器(Software Timer)的创建也分为动态创建和静态创建,同时创建成功之后,返回控制句柄函数原型如下。

动态创建

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

静态创建

TimerHandle_t xTimerCreate( const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction,StaticTimer_t *pxTimerBuffer );
const char * const pcTimerName 填定时器的名字
TickType_t xTimerPeriodInTicks, 填软件定时器执行周期,以Tick为单位
UBaseType_t uxAutoReload, pdTRUE代表为周期性定时器 pdFALSE 一次性定时器
void * pvTimerID 回调函数可以使用此参数, 比如分辨是哪个定时器
TimerCallbackFunction_t pxCallbackFunction, 填软件定时器执行函数
StaticTimer_t *pxTimerBuffer 回调函数可以使用此参数, 比如分辨是哪个定时器

创建软件定时器

static TimerHandle_t g_TimerSound;
void GameSoundTimer_Func(void)
{
}
g_TimerSound = xTimerCreate("GameSound",200,pdFALSE,NULL,GameSoundTimer_Func);

        首先需要声明一个句柄,然后声明或者找到,软件定时器的执行函数,选择软件定时器为周期性定时器或者一次性定时器,这里200个Tick可以看成200ms,来对待,还有给软件定时器七一给名字,基本上创建函数需要填写的参数就这么多。

启动/停止软件定时器

        启动软件定时器(Software Timer)就是将他的状态改变为 运行态(Running、Active),而停止软件定时器(Software Timer)就是对应的将状态改为 冬眠(Dormant) ,在这个状态软件定时器不能运行。

启动软件定时器

BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,BaseType_t *pxHigherPriorityTaskWoken );

        这个参数分为在普通任务上下文使用,和在中断任务上下文使用,参数有一位不同,具体参数填写见下表格。

TimerHandle_t xTimer 填写作用定时器的句柄
 TickType_t xTicksToWait 如果 command queue队列已满等待的时间
BaseType_t*pxHigherPriorityTaskWoken

pdFALSE当前没有更高优先级的任务需要运行

pdTrue 有更高优先级的任务在ISR结束时需要切换任务

        当调用启动函数的时候,软件定时器状态会从冬眠(Dormant)转变为 运行态(Running、Active),从而去运行任务。

停止软件定时器

        调用停止函数会使,软件定时器(Software Timer)从 运行态(Running、Active)停止转变为冬眠(Dormant)状态,从而停止定时器的功能。

BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );
BaseType_t xTimerStopFromISR( TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken );
TimerHandle_t xTimer 填写作用定时器的句柄
 TickType_t xTicksToWait 如果 command queue队列已满等待的时间
BaseType_t*pxHigherPriorityTaskWoken

pdFALSE当前没有更高优先级的任务需要运行

pdTrue 有更高优先级的任务在ISR结束时需要切换任务

static TimerHandle_t g_TimerSound;

void GameSoundTimer_Func(void)
{
}

g_TimerSound = xTimerCreate("GameSound",200,pdFALSE,NULL,GameSoundTimer_Func);

xTimerStart( g_TimerSound, 0);//开启软件定时器,如果阻塞就不等待

xTimerStop( g_TimerSound, 0);//关闭软件定时器,如果 command queue 队列阻塞不等待

改变软件定时器周期

        这里软件定时器在创建的时候,需要声明定时器周期,如果在后续-程序中,需要改变软件定时器的周期可以通过这个函数来改变周期,也就是执行时间,同时这里需要注意的是,这个函数也可以让软件定时器从冬眠(Dormant)转变为 运行态(Running、Active)

        当在软件定时器工作时调用,假设此时时间为tX,调用修改新的周期时间为y,那么软件定时器调用函数去响应的时间就是,tX+y,调用函数之前的时间不会计入新的软件定时器周期内。

函数原型

BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,TickType_t xNewPeriod,TickType_t xTicksToWait );
TimerHandle_t xTimer 填写改变定时器周期的句柄
TickType_t xNewPeriod 填写新的定时器周期
TickType_t xTicksToWait 等待 command queue超时时间
static TimerHandle_t g_TimerSound;

void GameSoundTimer_Func(void)
{
}

g_TimerSound = xTimerCreate("GameSound",200,pdFALSE,NULL,GameSoundTimer_Func);

xTimerChangePeriod(g_TimerSound,400,0);//更改定时器周期为400

xTimerStart( g_TimerSound, 0);//开启软件定时器,如果阻塞就不等待

xTimerStop( g_TimerSound, 0);//关闭软件定时器,如果 command queue 队列阻塞不等待

软件定时器复位函数

       当在软件定时器工作时调用,假设此时时间为tX,周期时间为n,那么软件定时器调用函数去响应的时间就是 tX+n, 这个函数也可以让软件定时器从冬眠(Dormant)转变为 运行态(Running、Active)

函数原型

BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );
TimerHandle_t xTimer 填写改变定时器周期的句柄
TickType_t xTicksToWait 等待 command queue超时时间
static TimerHandle_t g_TimerSound;

void GameSoundTimer_Func(void)
{
}

g_TimerSound = xTimerCreate("GameSound",200,pdFALSE,NULL,GameSoundTimer_Func);

xTimerChangePeriod(g_TimerSound,400,0);//更改定时器周期为400
xTimerReset( g_TimerSound,0 );//复位软件定时器,等待时间为0

xTimerStart( g_TimerSound, 0);//开启软件定时器,如果阻塞就不等待

xTimerStop( g_TimerSound, 0);//关闭软件定时器,如果 command queue 队列阻塞不等待

程序实现调用

static TimerHandle_t g_TimerSound;

void GameSoundTimer_Func(TimerHandle_t xTimer)
{
	PassiveBuzzer_Control(0);

}

int Buzzer_Init(void)
{
	//初始化蜂鸣器
  PassiveBuzzer_Init();
	//创建软件定时器
	g_TimerSound = xTimerCreate("GameSound",200,pdFALSE,NULL,GameSoundTimer_Func);	
}
void Buzzer_buzz(int freq ,int time_ms)
{
	PassiveBuzzer_Set_Freq_Duty(freq, 50);
	//启动软件定时器停止声音
	xTimerChangePeriod(g_TimerSound,time_ms,0);	
}

                                欢迎指正,希望对你,有所帮助!!!

上一篇:深入探讨ASP.NET Core中间件及其请求处理管道特性


下一篇:redis的zset实现下滑滚动分页查询思路