系列文章目录
文章目录
- 系列文章目录
- 软件定时器
- API函数
- 实验测试
软件定时器
定时器的作用:经过一段指定时间,触发超时事件
在裸机开发中,应用的是芯片自带的定时器模块,精度很高,在中断服务函数中处理信息,包括实现PWM等功能(硬件定时器)
软件定时器是指具有定时功能的软件,可以设置定时周期,在回调函数中进行信息处理,只要内存够可以创建非常多。
软件定时器优点:
硬件定时器数量有限,而软件定时器理论上只需有足够内存,就可以创建多个;
使用简单、成本低;
缺点:
软件定时器相对硬件定时器来说,精度没有那么高(因为它以系统时钟为基准,系统时钟中断优先级又是最低,容易被打断)。 对于需要高精度要求的场合,不建议使用软件定时器。
软件定时器特点:
可裁剪:使能软件定时器,需将configUSE_TIMERS 配置项配置成 1
单次和周期:软件定时器支持设置成:单次定时器或周期定时器
软件定时器服务任务的优先级为 configTIMER_TASK_PRIORITY = 31;
定时器的命令队列长度为 configTIMER_QUEUE_LENGTH = 5
要点:
1.软件定时器的超时回调函数是由软件定时器服务任务调用的,软件定时器的超时回调函数本身不是任务,因此不能在该回调函数中使用可能会导致任务阻塞的 API 函数。
2.在调用函数 vTaskStartScheduler()开启任务调度器的时候,会创建一个用于管理软件定时器的任务,prvTimerTask( ) ,这个任务就叫做软件定时器服务任务。
3.软件定时器的超时回调函数是在软件定时器服务任务中被调用的,服务任务不是专为某个定时器服务的,它还要处理其他定时器。回调函数要尽快实行,不能进入阻塞状态,即不能调用那些会阻塞任务的 API 函数,如:vTaskDelay() ,访问队列或者信号量的非零阻塞时间的 API 函数也不能调用。
工作方式:API函数通过往定时器队列写入消息,用户不能直接访问
软件定时器有两种状态:
休眠态:软件定时器可以通过其句柄被引用,但因为没有运行,所以其定时超时回调函数不会被执行
运行态:运行态的定时器,当指定时间到达之后,它的超时回调函数会被调用
新创建的软件定时器处于休眠状态 ,也就是未运行的!,只有发送命令队列后才行。
FreeRTOS提供了两种软件定时器:
单次定时器:单次定时器的一旦定时超时,只会执行一次其软件定时器超时回调函数,不会自动重新开启定时,不过可以被手动重新开启。
周期定时器:周期定时器的一旦启动以后就会在执行完回调函数以后自动的重新启动 ,从而周期地执行其软件定时器回调函数。
单次定时器:
周期定时器:
API函数
软件定时器句柄结构体成员:
typedef struct tmrTimerControl
{
const char * pcTimerName /* 软件定时器名字 */
ListItem_t xTimerListItem /* 软件定时器列表项 */
TickType_t xTimerPeriodInTicks; /* 软件定时器的周期 */
void * pvTimerID /* 软件定时器的ID */
TimerCallbackFunction_t pxCallbackFunction; /* 软件定时器的回调函数 */
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTimerNumber /* 软件定时器的编号,调试用 */
#endif
uint8_t ucStatus; /* 软件定时器的状态 */
} xTIMER;
常见的API函数:
函数 | 描述 |
---|---|
xTimerCreate() | 动态方式创建软件定时器 |
xTimerCreateStatic() | 静态方式创建软件定时器 |
xTimerStart() | 开启软件定时器定时 |
xTimerStartFromISR() | 在中断中开启软件定时器定时 |
xTimerStop() | 停止软件定时器定时 |
xTimerStopFromISR() | 在中断中停止软件定时器定时 |
xTimerReset() | 复位软件定时器定时 |
xTimerResetFromISR() | 在中断中复位软件定时器定时 |
xTimerChangePeriod() | 更改软件定时器的定时超时时间 |
xTimerChangePeriodFromISR() | 在中断中更改定时超时时间 |
1.创建软件定时器:
TimerHandle_t xTimerCreate( const char * const pcTimerName, //软件定时器名字
const TickType_t xTimerPeriodInTicks, //定时超时时间,单位:系统时钟节拍
const UBaseType_t uxAutoReload, //定时器模式,pdTRUE:周期定时器,pdFALSE:单次定时器
void * const pvTimerID, //软件定时器ID,用于多个如那件定时器公用一个回调函数
TimerCallbackFunction_t pxCallbackFunction ); //软件定时器超时回调函数
返回值:
NULL 创建失败
其他值:创建成功,返回其句柄
2.开启软件定时器
BaseType_t xTimerStart( TimerHandle_t xTimer,const TickType_t xTicksToWait );
形参:
xTimer:要开启的软件定时器句柄
xTickToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS:开启成功
pdFAIL:开启失败
3.停止软件定时器
BaseType_t xTimerStop( TimerHandle_t xTimer,const TickType_t xTicksToWait);
形参:
xTimer:软件定时器句柄
xTickToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS:停止成功
pdFAIL:停止失败
4.复位软件定时器
BaseType_t xTimerReset( TimerHandle_t xTimer,const TickType_t xTicksToWait);
形参:
xTimer:软件定时器句柄
xTickToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS:成功
pdFAIL:失败
5.更改软件定时器的超时时间
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
const TickType_t xNewPeriod,
const TickType_t xTicksToWait);
形参:
xTimer:软件定时器句柄
xNewPeriod:新的定时超时时间,单位:系统时钟节拍
xTickToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS:成功
pdFAIL:失败
实验测试
TimerHandle_t timer1_handle = 0; /* 单次定时器 */
TimerHandle_t timer2_handle = 0; /* 周期定时器 */
void timer1_callback( TimerHandle_t pxTimer );
void timer2_callback( TimerHandle_t pxTimer );
void vOtherFunction( void )
{
/* 单次定时器 */
timer1_handle = xTimerCreate( "timer1",
500,
pdFALSE,
(void *)1,
timer1_callback );
/* 周期定时器 */
timer2_handle = xTimerCreate( "timer2",
2000,
pdTRUE,
(void *)2,
timer2_callback );
xTaskCreate( vTaskCode, "tak1", 128, NULL, 1, &task1_handler );
vTaskStartScheduler();
}
void task1( void * pvParameters )
{
xTimerStart(timer1_handle,portMAX_DELAY);
xTimerStart(timer2_handle,portMAX_DELAY);
while(1)
{
vTaskDelay(10);
}
}
void task2( void * pvParameters )
{
while(1)
{
vTaskDelay(10);
}
}
/* timer1的超时回调函数 */
void timer1_callback( TimerHandle_t pxTimer )
{
static uint32_t timer = 0;
printf("timer1的运行次数:%d\r\n",++timer);
}
/* timer2的超时回调函数 */
void timer2_callback( TimerHandle_t pxTimer )
{
static uint32_t timer = 0;
printf("timer2的运行次数:%d\r\n",++timer);
}
周期性任务在不断执行,单次定时器只执行了一次。