首先介绍一下软件定时任务创建函数,代码如下所示所示的函数:
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t * pxTimerBuffer )
/* 使用动态分配内存的方法创建定时器
* pcTimerName:定时器名字, 用处不大, 尽在调试时用到
* xTimerPeriodInTicks: 周期, 以Tick为单位
* uxAutoReload: 类型, pdTRUE表示自动加载, pdFALSE表示一次性
* pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器
* pxCallbackFunction: 回调函数
* 返回值: 成功则返回TimerHandle_t, 否则返回NULL */
函数需要的入口参数中,最后一个入口参数就是回调函数,在定时时间到的时候,FreeRTOS内部创建的处理任务函数会调用这个回调函数。
FreeRTOS中有一个Tick中断,软件定时器基于Tick来运行。在哪里执行定时器函数?第一印象就是在Tick中断里执行: 在Tick中断中判断定时器是否超时
如果超时了,调用它的回调函数
但是上面的运行思想是错的,FreeRTOS是RTOS,它不允许在内核、在中断中执行不确定的代码:如果定时器函数很耗时,会影响整 个系统。所以,FreeRTOS中,不在Tick中断中执行定时器函数。
也就是用户对定时器函数的配置,都是通过队列传输给系统定义的prvTimerTask()任务函数,prvTimerTask()任务函数接收到队列中的数据之后,对应的做出相应的处理。
这里需要注意的是,打开宏configUSE_TIMERS之后,创建的prvTimerTask()任务函数必必须指定其相应的优先级和队列大小、堆栈的大小。
守护任务的调度,跟普通的任务并无差别。当守护任务是当前优先级最高的就绪态任务时,它就可以运行。它的工作有两类: 处理命令:从命令队列里取出命令、处理执行定时器的回调函数,能否及时处理定时器的命令、能否及时执行定时器的回调函数,严重依赖于守护任务的优先级。
定时器的回调函数的原型如下:
void ATimerCallback( TimerHandle_t xTimer );
设置主要是:创建、删除、启动、停止、复位、修改周期、设置定时器ID等。
使用定时器之前,需要做一些配置,主要是头文件中宏定义的配置,如下图所示:
配置使用定时器的时候出现xTimerTask()函数没有定义的情况,可能是以下几种原因:
1:相应的头文件没有引用,如果引用头文件的时候,发现有红色波浪线的报错,有可能是都应头文件的路径没有给。
2:xTimerTask()函数的裁剪宏定义没有开启,将这个部分裁剪了。
3:定时器的使能宏没有开启,导致的。
4:开启定时器的使能宏之后,会出现如下图所示的报错,这三个报错的意思就是:使能定时器之后,必须配置守护任务的优先级、命令队列的长度、守护任务栈的大小。
软件定时器配置好之后,需要使用xTimerStart(TimerHandle1,0);函数开启定时器,不然是不能运行的。
下面是软件定时器的使用demo,timer1是不循环的定时器,timer2是循环的定时器。
TimerHandle_t TimerHandle1;
TimerHandle_t TimerHandle2;
static void timer1Intterp(TimerHandle_t timer1)
{
printf("timer1 is doing\r\n");
}
static void timer2Intterp(TimerHandle_t timer2)
{
printf("timer2 is doing\r\n");
}
int main( void )
{
prvSetupHardware();
QueueUsart1=xQueueCreate(2,sizeof(int));
QueueUsart2=xQueueCreate(2,sizeof(int));
TimerHandle1=xTimerCreate("timer1",100,pdFALSE,0,timer1Intterp);
TimerHandle2=xTimerCreate("timer2",100,pdTRUE,0,timer2Intterp);
xTimerStart(TimerHandle1,0);
xTimerStart(TimerHandle2,0);
vTaskStartScheduler();
return 0;
}
下图是debug的调试结果:
按键消除抖动多采用的方式有两种: