freeRTOS中加入了软件定时器这个功能组件,是一个可选的、不属于freeRTOS内核的功能,由定时器服务(其实就是一个定时器任务)来提供。
软件定时器是当设定一个定时时间,当达到设定的时间之后就会执行指定的功能函数,而这个功能函数就叫做回调函数。
也就是说回调函数的两次执行间隔叫做定时器的定时周期。
回调函数:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
1、 freeRTOS中开启软件定时器功能
在freeRTOS中要使用软件定时器的话,需要在配置文件freeRTOSConfig.h中设置相应的宏,如下:
#define configUSE_TIMERS 1 //使能软件定时器
#define configTIMER_TASK_PRIORITY 2 // 软件定时器的优先级
#define configTIMER_QUEUE_LENGTH 10 // 软件定时器的队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) // 软件定时器的堆栈空间大小(单位是字)
2、freeRTOS的定时器种类
(1)单次定时器
单次定时器定时时间到了就执行一次回调函数,之后不会再执行,只有在再次重新启动的时候才会再执行一次。
(2)周期定时器
周期定时器根据设定的时间周期的执行的。
它一旦启动以后,每执行一次完一次回调函数以后定时器会自动重启,回调函数会周期性地执行。
单次定时器和周期定时器的示意图如下所示:
3、freeRTOS 软件定时器的API函数
3.1、创建软件定时器
TimerHandle_t xTimerCreate (
const char * const pcTimerName, /* 定时器名字 */
const TickType_t xTimerPeriod, /* 定时器周期 */
const UBaseType_t uxAutoReload, /* 选择单次模式或者周期模式 */
void * const pvTimerID, /* 定时器 ID */
TimerCallbackFunction_t pxCallbackFunction ); /* 定时器回调函数 */
函数描述:函数 xTimerCreate 用于创建软件定时器。
pcTimerName:定时器名字,一般用于调试,方便识别不同的定时器。
xTimerPeriod:定时器周期,单位是系统时钟节拍。
uxAutoReload:选择定时器是周期模式还是单次模式。若参数为 pdTRUE,则表示选择周期模式,若参数为 pdFALSE,则表示选择单次模式。
pvTimerID:定时器的 ID。当创建多个不同的定时器,但又使用同一个回调函数时,在回调函数中就可以通过不同的 ID 号来区分不同的定时器。
pxCallbackFunction:定时器的回调函数。
返回值:创建成功返回定时器的句柄,失败会返回 NULL。
创建一个单次触发的软件定时器示例如下:
TimerHandle_t singalTIMERS; //单次定时器
void singalTimersFunc(TimerHandle_t xTimers); //单次定时器回调函数
/*创建单次定时器*/
singalTIMERS = xTimerCreate(
"singalTIMERS", //软件定时器的名字
1000, //定时周期,单位是时钟节拍数
pdFALSE, //定时器模式,pdTRUE为周期定时器,//pdFALSE为单次定时器
(void*)1, //定时器的ID号
singalTimersFunc //定时器回调函数
);
3.2、启动软件定时器
1)在任务中启动
BaseType_t xTimerStart(
TimerHandle_t xTimer, /* 定时器句柄 */
TickType_t xBlockTime ); /* 成功启动定时器前的最大等待时间设置,单位系统时钟节拍 */
函数描述:函数 xTimerStart 用于启动软件定时器。
xTimer:是定时器句柄。
xBlockTime:是成功启动定时器前的最大等待时间设置,单位系统时钟节拍。
这是定时器组的大部分 API 函数不是直接运行的,而是通过消息队列给定时器任务发消息来实现的,
此参数设置的等待时间就是当消息队列已经满的情况下,等待消息队列有空间时的最大等待时间。
返回值:返回 pdFAIL 表示此函数向消息队列发送消息失败,返回 pdPASS 表示此函数向消息队列发 送消息成功。
注意:定时器任务实际执行消息队列发来的命令依赖于定时器任务的优先级,如果定时器任务 是高优先级会及时得到执行,如果是低优先级,就要等待其余高优先级任务释放 CPU 权才可以得到 执行。
使用这个函数要注意以下问题:
1> 要使用定时器启动函数前提是已经通过函数 xTimerCreate 成功创建了软件定时器。
2> 在 FreeRTOSConfig.h 文件中使能宏定义: #define configUSE_TIMERS 1
2)在中断中启动
BaseType_t xTimerStartFromISR(TimerHandle_t xTimer BaseType_t* pxHigherPriorityTaskWoken);
函数描述:
XTimer:软件定时器的句柄
pxHigherPriorityTaskWoken:退出此函数时是否要进行任务切换
返回值:
pdPASS:软件定时器开启成功。
pdFAIL:软件定时器开启失败。
3.3、停止定时器
1)在任务中停止软件定时器
BaseType_t xTimerStop(TimerHandle_t xTime, TickType_t xTicksToWait)
函数描述:
xTimer:软件定时器的句柄。
xTicksToWait:阻塞时间,即停止定时器最大的等待时间。
返回值:
pdPASS:软件定时器停止成功
pdFAIL:软件定时器停止失败
2)在中断中停止软件定时器
xTimerStopFormISR(TimerHandle_t xTimer, BaseType_t pxHigherPriorityTaskWoken);
函数描述:
xTimer:软件定时器句柄
pxHigherPriorityTaskWoken:退出此函数时是否要进行任务切换
返回值:
pdPASS:软件定时器开启成功。
pdFAIL:软件定时器开启失败。
3.4、复位定时器
1)在任务中复位
BaseType_t xTimerReset(TimerHandle_t xTimer, TickType_t xTicksToWait)
函数描述:
xTimer:软件定时器的句柄。
xTicksToWait:阻塞时间,即停止定时器最大的等待时间。
返回值:
pdPASS:软件定时器复位成功
pdFAIL:软件定时器复位失败
2)在中断中复位
BaseType_t xTimerResetFromISR(TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken);
函数描述:
xTimer:软件定时器句柄
pxHigherPriorityTaskWoken:退出此函数时是否要进行任务切换
返回值:
pdPASS:软件定时器复位成功。
pdFAIL:软件定时器复位失败。
3.5、查询定时器是否已经开始运行
BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
查询定时器以查看它是活动的还是休眠的。
如果出现以下情况,计时器将处于休眠状态:
1) 已创建但未启动。
2) 已过期的计时器尚未重新启动。
返回值:
pdFALSE,没有运行。
其他值,运行。
4、软件定时器使用实例
创建2个软件定时器,ID号分别为1、2,这两个软件定时器使用同一个回调函数,在回调函数里面读取定时器的ID,通过ID识别定时器。
1、创建软件定时器
TimerHandle_t SoftWaveTimer1; //软件定时器1
TimerHandle_t SoftWaveTimer2; //软件定时器2
void pxSoftWaveTimer(TimerHandle_t xTimer); //软件定时器回调函数
SoftWaveTimer1 = xTimerCreate(
"softwaveTimer1",
1000,
pdTRUE,
(void*)1,
pxSoftWaveTimer);
SoftWaveTimer2 = xTimerCreate(
"softwaveTimer2", //定时器句柄
3000, //定时器周期
pdTRUE, //周期/单次定时器
(void*)2, //定时器ID
pxSoftWaveTimer); //回调函数指针
2、定时器回调函数
void pxSoftWaveTimer(TimerHandle_t xTimer)
{
u32 TimerID;
u8 *TimerName;
TimerID = (u32)pvTimerGetTimerID(xTimer); //获取定时器ID
TimerName = (u8*)pcTimerGetName( xTimer ); //获取定时名字
if(TimerID == 1)
{
printf("软件定时器%s运行,1S周期\r\n",TimerName);
}
if(TimerID == 2)
{
printf("软件定时器%s运行,2S周期\r\n",TimerName);
}
}
3、启动、关闭定时器
//task1任务函数
void task1_task(void *pvParameters) //prio = 2
{
u8 keyVal = 0;
while(1)
{
keyVal = KEY_Scan(0);
if(keyVal == KEY0_PRES) //启动定时器
{
xTimerStart(SoftWaveTimer1,0);
xTimerStart(SoftWaveTimer2,0);
}
if(keyVal == KEY1_PRES) //关闭定时器
{
xTimerStop(SoftWaveTimer1,0);
xTimerStop(SoftWaveTimer2,0);
}
LED1 ^= 1;
vTaskDelay(200); //延时n个时钟节拍
}
}