一,软件定时器概述
软件定时器允许设置一段时间,当设定的时间到达之后就会执行指定的功能函数,被定时器调用的这个函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期。
二,回调函数的注意事项
回调函数是在定时器服务任务中执行的,因为定时器服务任务是由内核产生,无法由用户控制,所以本身的运行周期时间是固定的。
所以调用回调函数不可以调用有阻塞的函数API,eg.vTaskDelay()、vTaskDelayUntil()等,因为当执行定时器服务任务的回调函数里有这些函数,CPU就会被占用,使得定时器的任务无法得到处理其他定时器的超时任务【定时器服务任务负责管理和处理所有的软件定时器的超时事件】,当阻塞的事件过长的时候,会导致超时事件得不到处理,导致系统出现异常。
三.定时器命令队列
定时器命令队列是用户应用任务和定时器服务任务的一个媒介。
#define xTimerStart( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
tmrCOMMAND_START命令表示启动一个定时器,并通过定时器命令队列把相关信息传递给定时器服务任务,由定时器服务任务统一管理和执行。
定时器服务任务在接收到tmrCOMMAND_START命令后,会检查定时器句柄是否有效,如果有效则将该定时器加入定时器链表,并按照xTimeToWait指定的时间长度启动该定时器的超时计时器。同时,定时器服务任务会根据该定时器的超时时间和当前系统时间计算出该定时器的超时时间点,并在该时间点触发该定时器的回调函数。
四.软件定时器的属性
·单次定时器:当定时器开始启动,并且到达指定时间,回调函数只会执行一次,且定时器不会再自动重新启动,但会手动启动。
·周期定时器:当定时间隔到达之后,执行回调函数,还会自动重新启动,可以实现周期性的调用函数。
对于软件定时器我的理解:
软件定时器可以设定超时事件且不会和定时器服务任务产生冲突,因为FreeRTOS内核的定时器服务是基于软件定时器和系统时基(tick)实现的。定时器服务任务是一个高优先级任务,它负责处理所有的软件定时器事件。在系统启动时,定时器服务任务会被创建并开始运行,它以系统时基的时间间隔定期被调度执行。定时器服务任务的主要作用是从定时器消息队列中获取定时器事件,然后根据定时器事件的类型进行相应的处理,例如启动、停止、重置、删除定时器等。而定时器事件则由软件定时器生成,并通过xTimerChangePeriod()、xTimerStart()等函数向定时器服务任务发送。软件定时器提供了一种轻量级、灵活的机制,允许用户自定义定时器的超时时间。当软件定时器到达超时时间时,FreeRTOS内核会自动将该定时器的事件加入定时器消息队列中,等待定时器服务任务处理。
软件定时器开始运行,当设定的时间到了,会产生一个超时事件,将该事件放入到消息队列中,计数器此时会开始第二轮的计时,当等待的超时事件被执行的时候,也就是定时器服务任务执行的时候,计数器要暂停,等待服务任务执行结束,才会从原本暂停的计数值开始继续执行,当超时事件一直未被处理或者下一轮产生了新的超时事件,这个超时事件则会被舍弃。
当定时器到达超时时间后,若同时有多个定时器到期,则定时器服务任务会按照它们的超时时间先后顺序进行处理。如果某个定时器回调函数执行的时间过长导致定时器服务任务未及时处理其他超时事件,则可能会影响其他定时器的响应能力和精度。
超时事件的1个tick:1ms
#define configTICK_RATE_HZ (1000) //时钟节拍频率,这里设置为1000,周期就是1ms
五,函数介绍
1.xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
- xTimer:要启动的定时器的句柄,它是在调用 xTimerCreate() 函数创建定时器时返回的。
- xTicksToWait:等待定时器启动的最长时间。如果传递的值为 0,则该函数将立即返回,而不等待定时器启动;如果传递的值为 portMAX_DELAY,则该函数将一直等待,直到定时器启动。
- 调用 xTimerStart() 函数之后,定时器会开始计时,并且在每次计时器超时事件发生时,都会调用该定时器注册的回调函数。需要注意的是,在启动定时器之前,必须先通过 xTimerReset() 函数重置定时器的计数器,以确保定时器从指定的周期开始计时。
2.TimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );
- xTimer:要重置的定时器的句柄,它是在调用 xTimerCreate() 函数创建定时器时返回的。
- xTicksToWait:等待定时器重置的最长时间。如果传递的值为 0,则该函数将立即返回,而不等待定时器重置;如果传递的值为 portMAX_DELAY,则该函数将一直等待,直到定时器重置。
3.xTimerCreate( const char * pcTimerName, TickType_t xTimerPeriod, UBaseType_t uxAutoReload, void * pvTimerID, TimerCallbackFunction_t pxCallbackFunction );
- pcTimerName:定时器的名称,在调试和跟踪时使用。通常可以将其设置为 NULL。
- xTimerPeriod:定时器超时时间,单位是 tick。用于确定定时器超时事件的发生间隔。当定时器服务任务开始时,定时器计数器会被递减,直到达到 0,此时定时器超时事件就会发生。可以将该参数设置为 pdMS_TO_TICKS() 宏的值来将毫秒转换为 tick。
- uxAutoReload:是否需要自动重置计数器,并从头开始重新计时,以便创建一个循环定时器。如果将其设置为 0,则该定时器不会自动重置计数器,而是只会执行一次超时事件;否则,如果将其设置为 1,则该定时器将会自动重置计数器,并且在每个超时事件发生后,会按照设置的周期再次触发超时事件。
- pvTimerID:一个指向任意类型数据的指针,用于指定应该在计时器超时事件中传递的数据。如果不需要传递数据,则可以将其设置为 NULL。
- pxCallbackFunction:一个指向定时器超时事件回调函数的指针。当定时器计数器达到 0 时,定时器服务任务会调用此函数。在该函数中,可以编写相关的任务代码来执行所需的操作,例如发出信号量或将任务加入队列等。
4.xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );
- xTimer:要停止的定时器的句柄,它是在调用 xTimerCreate() 函数创建定时器时返回的。
- xTicksToWait:等待该定时器停止的最长时间。如果传递的值为 0,则该函数将立即返回,而不等待定时器停止;如果传递的值为 portMAX_DELAY,则该函数将一直等待,直到定时器停止。