• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 软件定时器
2
3
4## 基本概念
5
6软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数值后会触发用户定义的回调函数。定时精度与系统Tick时钟的周期有关。
7
8硬件定时器受硬件的限制,数量上不足以满足用户的实际需求,因此为了满足用户需求,提供更多的定时器,OpenHarmony LiteOS-M内核提供软件定时器功能。软件定时器扩展了定时器的数量,允许创建更多的定时业务。
9
10软件定时器功能上支持:
11
12- 静态裁剪:能通过宏关闭软件定时器功能。
13
14- 软件定时器创建。
15
16- 软件定时器启动。
17
18- 软件定时器停止。
19
20- 软件定时器删除。
21
22- 软件定时器剩余Tick数获取。
23
24
25## 运行机制
26
27软件定时器是系统资源,在模块初始化的时候已经分配了一块连续的内存,系统支持的最大定时器个数由los_config.h中的LOSCFG_BASE_CORE_SWTMR_LIMIT宏配置,该值按产品实际需要设定。
28
29软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先被触发的准则。
30
31软件定时器以Tick为基本计时单位,当用户创建并启动一个软件定时器时,OpenHarmony LiteOS-M内核会根据当前系统Tick时间及用户设置的定时间隔确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。
32
33当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,看是否有定时器超时,若有则将超时的定时器记录下来。
34
35Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用之前记录下来的定时器的超时回调函数。
36
37
38### 定时器状态
39
40- OS_SWTMR_STATUS_UNUSED(未使用)
41  系统在定时器模块初始化的时候将系统中所有定时器资源初始化成该状态。
42
43- OS_SWTMR_STATUS_CREATED(创建未启动/停止)
44  在未使用状态下调用LOS_SwtmrCreate接口或者启动后调用LOS_SwtmrStop接口后,定时器将变成该状态。
45
46- OS_SWTMR_STATUS_TICKING(计数)
47  在定时器创建后调用LOS_SwtmrStart接口,定时器将变成该状态,表示定时器运行时的状态。
48
49
50### 定时器模式
51
52OpenHarmony LiteOS-M内核的软件定时器提供三类定时器机制:
53
54- 第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。
55
56- 第二类是周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动地停止定时器,否则将永远持续执行下去。
57
58- 第三类也是单次触发定时器,但与第一类不同之处在于这类定时器超时后不会自动删除,需要调用定时器删除接口删除定时器。
59
60
61## 接口说明
62
63OpenHarmony LiteOS-M内核的软件定时器模块提供下面几种功能,接口详细信息可以查看API参考。
64
65  **表1** 软件定时器接口
66
67| 功能分类 | 接口描述 |
68| -------- | -------- |
69| 创建、删除定时器 | -&nbsp;LOS_SwtmrCreate:创建定时器。<br/>-&nbsp;LOS_SwtmrDelete:删除定时器。 |
70| 启动、停止定时器 | -&nbsp;LOS_SwtmrStart:启动定时器。<br/>-&nbsp;LOS_SwtmrStop:停止定时器。 |
71| 获得软件定时器剩余Tick数 | LOS_SwtmrTimeGet:获得软件定时器剩余Tick数。 |
72
73
74## 开发流程
75
76软件定时器的典型开发流程:
77
781. 配置软件定时器。
79   - 确认配置项LOSCFG_BASE_CORE_SWTMR和LOSCFG_BASE_IPC_QUEUE为1打开状态;
80   - 配置LOSCFG_BASE_CORE_SWTMR_LIMIT最大支持的软件定时器数;
81   - 配置OS_SWTMR_HANDLE_QUEUE_SIZE软件定时器队列最大长度;
82
832. 创建定时器LOS_SwtmrCreate。
84   - 创建一个指定计时时长、指定超时处理函数、指定触发模式的软件定时器;
85   - 返回函数运行结果,成功或失败;
86
873. 启动定时器LOS_SwtmrStart。
88
894. 获得软件定时器剩余Tick数LOS_SwtmrTimeGet。
90
915. 停止定时器LOS_SwtmrStop。
92
936. 删除定时器LOS_SwtmrDelete。
94
95> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
96> - 软件定时器的回调函数中不要做过多操作,不要使用可能引起任务挂起或者阻塞的接口或操作。
97>
98> - 软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级设定为0,且不允许修改  。
99>
100> - 系统可配置的软件定时器资源个数是指:整个系统可使用的软件定时器资源总个数,而并非是用户可使用的软件定时器资源个数。例如:系统软件定时器多占用一个软件定时器资源数,那么用户能使用的软件定时器资源就会减少一个。
101>
102> - 创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源。
103>
104> - 创建单次不自删除属性的定时器,用户需要调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。
105
106
107## 编程实例
108
109
110### 实例描述
111
112在下面的例子中,演示如下功能:
113
1141. 软件定时器创建、启动、删除、暂停、重启操作。
115
1162. 单次软件定时器,周期软件定时器使用方法。
117
118
119### 示例代码
120
121前提条件:
122
123- 在los_config.h中,将LOSCFG_BASE_CORE_SWTMR配置项打开。
124
125- 在los_config.h中,将LOSCFG_BASE_CORE_SWTMR_ALIGN配置项关闭,示例代码中演示代码不涉及定时器对齐。
126
127- 配置好LOSCFG_BASE_CORE_SWTMR_LIMIT最大支持的软件定时器数。
128
129- 配置好OS_SWTMR_HANDLE_QUEUE_SIZE软件定时器队列最大长度。
130
131代码实现如下:
132
133本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleSwtmr。
134
135
136```
137#include "los_swtmr.h"
138
139/* 定时器间隔时间 */
140#define SWTMR_INTERVAL_LONG      1000
141#define SWTMR_INTERVAL_SHORT     100
142
143/* 定时器触发次数计数 */
144UINT32 g_timerCount1 = 0;
145UINT32 g_timerCount2 = 0;
146
147/* 回调函数1,单次触发定时器的回调函数 */
148void Timer1Callback(UINT32 arg)
149{
150    g_timerCount1++;
151    printf("g_timerCount1=%d\n", g_timerCount1);
152}
153
154/* 回调函数2,多次触发定时器的回调函数 */
155void Timer2Callback(UINT32 arg)
156{
157    g_timerCount2++;
158    printf("g_timerCount2=%d\n", g_timerCount2);
159}
160
161void SwtmrTest(void)
162{
163    UINT32 ret;
164    UINT32 id1; // 定时器id1,单次触发定时器
165    UINT32 id2; // 定时器id2,周期触发定时器
166    UINT32 tickCount;
167
168#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)
169    /* 创建单次软件定时器,Tick数为1000,启动到1000Tick数时执行回调函数1 */
170    LOS_SwtmrCreate(SWTMR_INTERVAL_LONG, LOS_SWTMR_MODE_ONCE, Timer1Callback, &id1, 0,
171                    OS_SWTMR_ROUSES_IGNORE, OS_SWTMR_ALIGN_SENSITIVE);
172
173    /* 创建周期性软件定时器,每100Tick数执行回调函数2 */
174    LOS_SwtmrCreate(SWTMR_INTERVAL_SHORT, LOS_SWTMR_MODE_PERIOD, Timer2Callback, &id2, 0,
175                    OS_SWTMR_ROUSES_IGNORE, OS_SWTMR_ALIGN_SENSITIVE);
176#else
177    /* 创建单次软件定时器,Tick数为1000,启动到1000Tick数时执行回调函数1 */
178    LOS_SwtmrCreate(SWTMR_INTERVAL_LONG, LOS_SWTMR_MODE_ONCE, Timer1Callback, &id1, 0);
179
180    /* 创建周期性软件定时器,每100Tick数执行回调函数2 */
181    LOS_SwtmrCreate(SWTMR_INTERVAL_SHORT, LOS_SWTMR_MODE_PERIOD, Timer2Callback, &id2, 0);
182#endif
183
184    /* 启动单次软件定时器 */
185    ret = LOS_SwtmrStart(id1);
186    printf("start Timer1 %s\n", (ret == LOS_OK) ? "success" : "failed");
187
188    /* 短时间延时,定时器还未触发 */
189    LOS_TaskDelay(SWTMR_INTERVAL_SHORT);
190
191    /* 单次定时器还未到时间触发,此时停止应该成功 */
192    ret = LOS_SwtmrStop(id1);
193    printf("stop timer1 %s\n", (ret == LOS_OK) ? "success" : "failed");
194
195    LOS_SwtmrStart(id1);
196
197    /* 长时间延时,定时器触发 */
198    LOS_TaskDelay(SWTMR_INTERVAL_LONG);
199
200    /* 单次定时器触发后自删除,此时停止失败才是正常 */
201    ret = LOS_SwtmrStop(id1);
202    printf("timer1 self delete test %s\n", (ret != LOS_OK) ? "success" : "failed");
203
204    /* 启动周期性软件定时器 */
205    ret = LOS_SwtmrStart(id2);
206    printf("start Timer2 %s\n", (ret == LOS_OK) ? "success" : "failed");
207
208    /* 长时间延时,定时器周期触发 */
209    LOS_TaskDelay(SWTMR_INTERVAL_LONG);
210
211    LOS_SwtmrStop(id2);
212
213    ret = LOS_SwtmrDelete(id2);
214    if (ret == LOS_OK) {
215        printf("delete Timer2 success\n");
216    }
217}
218
219UINT32 ExampleSwtmr(VOID)
220{
221    UINT32 ret;
222    TSK_INIT_PARAM_S taskParam = { 0 };
223    UINT32 taskId;
224
225    /* 锁任务调度 */
226    LOS_TaskLock();
227
228    /* 创建任务 */
229    taskParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SwtmrTest;
230    taskParam.pcName       = "TimerTsk";
231    taskParam.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
232    taskParam.usTaskPrio   = 5;
233    ret = LOS_TaskCreate(&taskId, &taskParam);
234    if (ret != LOS_OK) {
235        printf("TimerTsk create failed.\n");
236        return LOS_NOK;
237    }
238
239    /* 解锁任务调度 */
240    LOS_TaskUnlock();
241    return LOS_OK;
242}
243```
244
245
246### 结果验证
247
248编译烧录运行,输出结果如下:
249
250
251```
252start Timer1 success
253stop timer1 success
254g_timerCount1=1
255timer1 self delete test success
256start Timer2 success
257g_timerCount2=1
258g_timerCount2=2
259g_timerCount2=3
260g_timerCount2=4
261g_timerCount2=5
262g_timerCount2=6
263g_timerCount2=7
264g_timerCount2=8
265g_timerCount2=9
266g_timerCount2=10
267delete Timer2 success
268```
269