前言:本文参考,韦东山开发文档,连接放在最后
基本概念理解
软件定时器(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);
}
欢迎指正,希望对你,有所帮助!!!