l 软件定时器的基本概念

定时器,是指从指定的时刻开始,经过一个指定时间,然后触发一个超时事件,用户可以自定义定时器的周期与频率。类似生活中的闹钟,我们可以设置闹钟每天什么时候响,还能设置响的次数,是响一次还是每天都响。

使用硬件定时器时,每次在定时时间到达之后就会自动触发一个中断,用户在中断中处理信息;而使用软件定时器时,需要我们在创建软件定时器时指定时间到达后要调用的函数(也称超时函数/回调函数),在回调函数中处理信息。软件定时器的回调函数类似硬件的中断服务函数,所以回调函数也要快进快出,而且回调函数中不能有任何阻塞任务运行的情况(软件定时器回调函数的上下文环境是任务)。

单次模式:当用户创建了定时器并启动了定时器后,定时时间到了,只执行一次回调函数之后就将该定时器进入休眠状态,不再重新执行。周期模式:这个定时器会按照设置的定时时间循环执行回调函数,直到用户将定时器删除。

jquery 定时器自动调用 jquery定时器用法_威纶通定时循环操作宏

FreeRTOS 通过一个 prvTimerTask 任务(也叫守护任务 Daemon)管理软定时器,它是在启动调度器时自动创建的, 为了满足用户定时需求。prvTimerTask 任务会在其执行期间检查用户启动的时间周期溢出的定时器,并调用其回调函数。

l 软件定时器的运作机制

软件定时器是可选的系统资源,在创建定时器的时候会分配一块内存空间。当用户创建并启动一个软件定时器时, FreeRTOS 会根据当前系统时间及用户设置的定时确定该定时器唤醒时间,并将该定时器控制块挂入软件定时器列表, FreeRTOS 中采用两个定时器列表维护软件定时器, pxCurrentTimerList 与 pxOverflowTimerList 是列表指针, 在初始化的时候分别指向 xActiveTimerList1 与 xActiveTimerList2。

同时, FreeRTOS 的软件定时器还有采用消息队列进行通信, 利用“ 定时器命令队列”向软件定时器任务发送一些命令,任务在接收到命令就会去处理命令对应的程序,比如启动定时器,停止定时器等。假如定时器任务处于阻塞状态,我们又需要马上再添加一个软件定时器的话,就是采用这种消息队列命令的方式进行添加,才能唤醒处于等待状态的定时器任务,并且在任务中将新添加的软件定时器添加到软件定时器列表中,所以,在定时器启动函数中, FreeRTOS 是采用队列的方式发送一个消息给软件定时器任务,任务被唤醒从而执行接收到的命令。

jquery 定时器自动调用 jquery定时器用法_uniapp 定时执行_02

l 软件定时器的回调函数中应快进快出,绝对不允许使用任何可能引软件定时器起任务挂起或者阻塞的 API 接口,在回调函数中也绝对不允许出现死循环。

l 软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级默认为 configTIMER_TASK_PRIORITY,为了更好响应,该优先级应设置为所有任务中最高的优先级。

l 创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源。

l 定时器任务的堆栈大小默认为 configTIMER_TASK_STACK_DEPTH 个字节。

l 软件定时器控制块

软件定时器虽然不属于内核资源,但是也是 FreeRTOS 核心组成部分,是一个可以裁剪的功能模块,同样在系统中由一个控制块管理其相关信息,软件定时器的控制块中包含没用过创建的软件定时器基本信息,在使用定时器前我们需要通过xTimerCreate()/xTimerCreateStatic()函数创建一个软件定时器,在函数中, FreeRTOS 将向系统管理的内存申请一块软件定时器控制块大小的内存用于保存定时器的信息。

l 软件定时器创建函数 xTimerCreate()

软件定时器与 FreeRTOS 内核其他资源一样,需要创建才允许使用的, FreeRTOS 为我们提供了两种创建方式,一种是动态创建软件定时器 xTimerCreate(), 另一种是静态创建方式 xTimerCreateStatic(),并返回一个句柄。

l 软件定时器启动函数

² xTimerStart():

在系统开始运行的时候,系统会帮我们自动创建一个软件定时器任务( prvTimerTask),在这个任务中,如果暂时没有运行中的定时器,任务会进入阻塞态等待命令, 而我们的启动函数就是通过“定时器命令队列” 向定时器任务发送一个启动命令,定时器任务获得命令就解除阻塞,然后执行启动软件定时器命令。

² xTimerStartFromISR()

除在任务启动软件定时器之外,还有在中断中启动软件定时器的函数xTimerStartFromISR()。xTimerStartFromISR()是函数 xTimerStart()的中断版本, 用于启动一个先前由函数 xTimerCreate() / xTimerCreateStatic()创建的软件定时器。

l 软件定时器停止函数

² xTimerStop()

xTimerStop() 用于停止一个已经启动的软件定时器, 该函数的实现也是通过“定时器命令队列”发送一个停止命令给软件定时器任务,从而唤醒软件定时器任务去将定时器停止。

jquery 定时器自动调用 jquery定时器用法_vc++ 类 定时器api_03

² xTimerStopFromISR()

xTimerStopFromISR()是函数 xTimerStop()的中断版本, 用于停止一个正在运行的软件定时器, 让其进入休眠态, 实现过程也是通过“定时器命令队列”向软件定时器任务发送停止命令。

jquery 定时器自动调用 jquery定时器用法_威纶通定时循环操作宏_04

l 软件定时器任务

软件定时器回调函数运行的上下文环境是任务,软件定时器任务是在系统开始调度( vTaskStartScheduler()函数) 的时候就被创建的,前提是将宏定义 configUSE_TIMERS 开启。

l 软件定时器删除函数 xTimerDelete()

xTimerDelete()用于删除一个已经被创建成功的软件定时器, 删除之后就无法使用该定时器, 并且定时器相应的资源也会被系统回收释放。

jquery 定时器自动调用 jquery定时器用法_uniapp 定时执行_05

l 软件定时器实验

软件定时器实验是在 FreeRTOS 中创建了两个软件定时器,其中一个软件定时器是单次模式, 5000 个 tick 调用一次回调函数,另一个软件定时器是周期模式, 1000 个 tick 调用一次回调函数,在回调函数中输出相关信息,

jquery 定时器自动调用 jquery定时器用法_威纶通定时循环操作宏_06

 定时器1每秒执行一次,定时器2单次执行(5秒)

jquery 定时器自动调用 jquery定时器用法_uniapp 定时执行_07

 实验效果

jquery 定时器自动调用 jquery定时器用法_jQuery 一次定时器_08

从结果上来看,虽然实现了功能,但是定时的精度差太远了。1秒中都定时出了2秒多,,,这显然是不可接受的。前后试过将心跳频率提高/降低都无法提升时间的精度,这个时间的误差都没变化。

在滴答时钟里面每50ms中断一次,时间基准就不对

jquery 定时器自动调用 jquery定时器用法_jQuery 一次定时器_09

也不知道这个空闲模式里面到底干了啥,验证影响了程序的定时准确度

jquery 定时器自动调用 jquery定时器用法_vc++ 类 定时器api_10

关掉空闲模式,这样下来时间就很准了

jquery 定时器自动调用 jquery定时器用法_jQuery 一次定时器_11

原来这是低功耗配置,也就是每个tick不一定会进入。

jquery 定时器自动调用 jquery定时器用法_jQuery 一次定时器_12

Hankin

2020.10.05