LV01-01-AliOSThings-14-软件定时器-04-软件定时器和RTC使用实例

本文主要是软件定时器——软件定时器和RTC使用实例的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows版本 windows11
Ubuntu版本 Ubuntu22.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
点击查看本文参考资料
分类 网址 说明
官方网站 阿里云 阿里云官网主页
阿里生活物联平台 生活物联网平台(飞燕平台)主页
AliGenie 天猫精灵开放平台AliGenie主页
阿里物联网平台 阿里物联网平台主页
Bluetooth 技术网站 蓝牙协议规范什么的可以来这里找
Telink Telink | Chips for a Smarter IoT (telink-semi.com)
Telink中文官网
开发手册 AliOS Things开发指南 AliOS Things开发指南,这里是最新版本,可以直接从官网找到
AliOS Things开发指南 AliOS Things应用开发指南,这里应该是3.3版本的完整开发文档
AliOS Things开发指南(3.0) AliOS Things应用开发指南,这里应该是3.0版本的完整开发文档
生活物联网平台开发文档 生活物联网平台(飞燕平台)开发文档
《设备端开发指南》
Wi-Fi IoT品类定义与功能开发 天猫精灵IoT开放平台——Wi-Fi IoT品类定义与功能开发
硬件平台 mk3080 WiFi开发板 WiFi开发板使用指南-阿里云开发者社区
esp8266开发板 一个教程:ESP8266-NodeMCU开发板详解-太极创客 (taichi-maker.com)
TLSR8258 Datasheet Datasheet for Telink BLE + IEEE802.15.4 MultiStandard Wireless SoC TLSR8258
参考资料 AliOS Things 3.0 应用开发指南 这个只是一篇参考文章,里面是一些环境搭建相关的,可以参考
IP知识百科 - 华为 (huawei.com) IP的一些相关知识点
点击查看相关文件下载
分类 网址 说明
蓝牙规范相关文档 Core Specification 5.2 核心规格 5.2,该规范定义了创建可互操作的Bluetooth 设备所需的技术。
《Core_v5.2.pdf》
Mesh Model(v1.1) 本Bluetooth 规范定义了模型(以及它们所需的状态和消息),这些模型用于在mesh 网络中的节点上执行基本功能,超出了Bluetooth Mesh 配置文件 规范中定义的基础模型。
本规范包括定义跨设备类型标准功能的通用模型,以及支持关键mesh 场景的模型,如照明控制、传感器、时间和场景。
《MshMDL_v1.1.pdf》
Mesh Profile(v1.0.1) 该Bluetooth 规范定义了基本要求,以实现可互操作的mesh 网络解决方案,用于Bluetooth 低能量无线技术。
《MshPRFv1.0.1.pdf》
Mesh Device Properties 本规范包含Bluetooth Mesh 配置文件 和Bluetooth Mesh 模型规范所要求的设备属性的定义。
但是跟之前的有些区别,我主要看的之前的版本:《MMeshDeviceProperties_v1.2.pdf》
GATT Specification Supplement GATT Specification Supplement | Bluetooth® Technology Website。
好像可以在线看:《GATT Specification Supplement》
Assigned Numbers GATT的一些类型定义可以在这里找。
AliOS Things alios-things/AliOS-Things Gitee上的AliOSThings SDK源码仓库
alibaba/AliOS-Things GitHub上的AliOSThings SDK源码仓库
天猫精灵蓝牙Mesh协议栈 alibaba-archive/genie-bt-mesh-stack GitHub上的天猫精灵蓝牙Mesh协议栈源码仓库。
之前是在alibaba/genie-bt-mesh-stack这个仓库。
写笔记的时候最新提交为faf523618a6a2560090fc423222b9db80984bb7a
蓝牙Mesh设备开发指南 阿里云生活服务平台开发手册——蓝牙设备开发一节中的内容

本节使用的开发板为mk3080开发板。

一、闹钟之CMD设计

1. 需求分析

image-20201012110952497

我们现在要在mk3080上实现这样一个功能,就是可以在cli命令行终端设置闹钟的参数,闹钟时间到可以打印相关数据。

2. 闹钟功能展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# date help  
Usage: date [OPTIONS] COMMAND [ARGS]

Options:
help : show date help

Command:
-r : read date
-s : set date
date -s Args:
Arags : xx:xx:xx

# alarm help
Usage: alarm [OPTIONS] COMMAND [ARGS]

Options:
help : show alarm help

Command:
-s : set alarm
date -s Args:
Arags : xx:xx:xx

二、相关实例

1. 软件定时器

可以看这里:helloworld_mk3080/example/06_timer_new.c · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

2. RTC

注意使用RTC的时候要修改一下HAL库,保证初始化函数正常返回,demo源码可以看这里:helloworld_mk3080/example/06_rtc_demo.c · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

三、闹钟实现

1. 计算闹钟时间

image-20231209124931182

软件定时器是基于系统的tick,它使用的是ms值,闹钟的定时时间需要换算成软件定时器的定时参数,也就是要换算成延时需要少个tick值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static uint32_t count_alarm_interval(ALARM_TIME alarmTime)
{
int ret = -1;
int32_t alarm_time_tick = 0;
int32_t real_time_tick = 0;
rtc_time_t time_buf = {0};

/* get current time */
ret = hal_rtc_get_time(&rtc0, &time_buf);
if (ret != 0)
{
printf("get time error !\n");
return;
}
//计算闹钟和当前时间对应的ms数
alarm_time_tick = alarmTime.hours*60*60*1000+alarmTime.minute*60*1000+alarmTime.second*1000;
real_time_tick = time_buf.hr*60*60*1000+time_buf.min*60*1000+time_buf.sec*1000;
printf("alarm_time_tick=%dms real_time_tick=%dms\r\n", alarm_time_tick, real_time_tick);
//判断闹钟是否大于当前的实时时钟
if(alarm_time_tick - real_time_tick >= 0)
{
return (alarm_time_tick - real_time_tick);//闹钟-实时时钟的差值
}
else
{
return (24*60*60*1000 + real_time_tick - alarm_time_tick);//一天ms数+实时时钟-闹钟
}
}

闹钟的时间参数是要和rtc实时时钟进行比较的,所以需要获取一次当前的rtc时间,在这里实时时钟rtc的时间我们需要将其换算为ms为单位,闹钟的时间也要换算,两者的差值就是软件定时器的定时参数。但是这里有一个问题,就是时间先后,比如说现在RTC的时间为12:00:00,我们现在定时在12:00:05,这样在5秒后,软件定时器的定时时间就到了,但是若是我们闹钟为11:59:55秒,那么此时其实闹钟时间是滞后于当前时间的,所以这个11:59:55的闹钟应该是在第二天的这个时间到,这个软件定时器的定时参数就是一天的ms数加上当前时间的ms数再减去闹钟时间的ms数。

2. 软件定时器

image-20231209125719283

我们配置好闹钟时间后就需要创建软件定时器,这里可以参数设置为0,也就是闹钟只生效一次。

3. 闹钟源码

以下为闹钟实现的源码,也可以看这里:helloworld_mk3080/example/06_alarm.c · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/** =====================================================
* Copyright © hk. 2022-2025. All rights reserved.
* File name : 06_alarm.c
* Author : 上上签
* Date : 2023-12-09
* Version :
* Description:
* ======================================================
*/

#include <stdio.h>
#include <stdlib.h>
#include <aos/kernel.h>
#include <k_api.h>
#include "aos/init.h"
#include "board.h"

#include "ulog/ulog.h"
#include "aos/cli.h"

#include "aos/hal/gpio.h"
#include "aos/hal/rtc.h"

#define RED_LED 0 // PA14
#define GRE_LED 1 // PA15
#define MODULE_NAME "rtc_app" /* module name used by ulog */
#define PORT_RTC_0 0
static gpio_dev_t led_gpio_dev[2] = {0};
static rtc_dev_t rtc0;
aos_timer_t *pAlarmTimer = NULL;
typedef struct __ALARM_TIME_
{
int hours;
int minute;
int second;
}ALARM_TIME;

static ALARM_TIME alarm_time = {0};

int led_init(void)
{
//由于PA14时rtl8710的jtag接口,我要使用GPIO功能,必须先关闭jtag借口
sys_jtag_off();
led_gpio_dev[0].port = RED_LED;
led_gpio_dev[0].config = OUTPUT_PUSH_PULL;
led_gpio_dev[0].priv = NULL;
//gpio PA14初始化
hal_gpio_init(&led_gpio_dev[0]);

led_gpio_dev[1].port = GRE_LED;
led_gpio_dev[1].config = OUTPUT_PUSH_PULL;
led_gpio_dev[1].priv = NULL;
//gpio PA14初始化
hal_gpio_init(&led_gpio_dev[1]);

return 0;
}

void hal_rtc_app_init(void)
{
int ret = -1;

rtc_config_t rtc_cfg;
rtc_time_t time_buf;

/* rtc port set */
rtc0.port = PORT_RTC_0;

/* set to DEC format */
rtc0.config.format = HAL_RTC_FORMAT_DEC;

/* init rtc0 with the given settings */
ret = hal_rtc_init(&rtc0);
if (ret != 0) {
printf("rtc init error !\n");
return;
}

time_buf.sec = 0;
time_buf.min = 49;
time_buf.hr = 10;
time_buf.weekday = 6;
time_buf.date = 9;
time_buf.month = 12;
time_buf.year = 2023;

/* set rtc0 time to 2020/2/26,21:31:00 */
ret = hal_rtc_set_time(&rtc0, &time_buf);
if (ret != 0) {
printf("rtc0 set time error !\n");
return;
}
printf("set time is: %4d-%02d-%02d %02d:%02d:%02d\r\n", time_buf.year, time_buf.month,
time_buf.date, time_buf.hr, time_buf.min, time_buf.sec);
}

void hal_rtc_app_gettime(void)
{
int ret = -1;
rtc_time_t time_buf;

/* get current time */
ret = hal_rtc_get_time(&rtc0, &time_buf);
if (ret != 0) {
printf("get time error !\n");
return;
}

printf("current time is: %4d-%02d-%02d %02d:%02d:%02d\r\n", time_buf.year, time_buf.month,
time_buf.date, time_buf.hr, time_buf.min, time_buf.sec);
}

/**
* timer callback function.
* The current use case is executed every 1300ms.
*/
static void timer1_func(void *timer, void *arg)
{
if(pAlarmTimer == NULL)
{
LOGE(MODULE_NAME, "pAlarmTimer is null!");
return;
}
/*
* Warning: an interface that causes a block is not allowed to be called within this function.
* Blocking within this function will cause other timers to run incorrectly.
* The printf function may also block on some platforms, so be careful how you call it.
*/
LOGI(MODULE_NAME, "[timer_new]timer expires!");
aos_timer_stop(pAlarmTimer);//只运行一次
}

static uint32_t count_alarm_interval(ALARM_TIME alarmTime)
{
int ret = -1;
int32_t alarm_time_tick = 0;
int32_t real_time_tick = 0;
rtc_time_t time_buf = {0};

/* get current time */
ret = hal_rtc_get_time(&rtc0, &time_buf);
if (ret != 0)
{
printf("get time error !\n");
return;
}
//计算闹钟和当前时间对应的ms数
alarm_time_tick = alarmTime.hours*60*60*1000+alarmTime.minute*60*1000+alarmTime.second*1000;
real_time_tick = time_buf.hr*60*60*1000+time_buf.min*60*1000+time_buf.sec*1000;
printf("alarm_time_tick=%dms real_time_tick=%dms\r\n", alarm_time_tick, real_time_tick);
//判断闹钟是否大于当前的实时时钟
if(alarm_time_tick - real_time_tick >= 0)
{
return (alarm_time_tick - real_time_tick);//闹钟-实时时钟的差值
}
else
{
return (24*60*60*1000 + real_time_tick - alarm_time_tick);//一天ms数+实时时钟-闹钟
}
}

static void timer_time_change(int nms)
{
if(pAlarmTimer == NULL)
{
LOGE(MODULE_NAME, "pAlarmTimer is null!");
return;
}
/* stop the timer before modifying the timer parameter */
aos_timer_stop(pAlarmTimer);

/* the timer cycle is modified to nms */
aos_timer_change(pAlarmTimer, nms);

/* start the timer after the timer parameter modification is complete */
aos_timer_start(pAlarmTimer);
}

static void date_help_show(void)
{
printf("Usage: date [OPTIONS] COMMAND [ARGS]\r\n");
printf("\r\n");
printf("Options:\r\n");
printf("help : show date help\r\n");
printf("\r\n");
printf("Command:\r\n");
printf("-r : read date\n");
printf("-s : set date\r\n");
printf("date -s Args: \r\n");
printf("Arags : xx:xx:xx\r\n");
}

static void alarm_help_show(void)
{
printf("Usage: alarm [OPTIONS] COMMAND [ARGS]\r\n");
printf("\r\n");
printf("Options:\r\n");
printf("help : show alarm help\r\n");
printf("\r\n");
printf("Command:\r\n");
printf("-r : read alarm\n");
printf("-s : set alarm\r\n");
printf("alarm -s Args: \r\n");
printf("Arags : xx:xx:xx\r\n");
}

static void date_cmd(char *buf, int32_t len, int32_t argc, char **argv)
{
int ret = 0;
rtc_time_t time_buf = {0};
char *ptimeIndex = NULL;
char s_Hours[20] = {0};
char s_Minutes[20] = {0};
char s_Seconds[20] = {0};

if(argc == 2)
{
if(strcmp(argv[0], "date"))
{
printf("cmd is error!plese retry!\r\n");
return ;
}

if(strcmp(argv[1], "help") == 0)
{
date_help_show();
}
else if(strcmp(argv[1], "-r") == 0)
{
//read date
ret = hal_rtc_get_time(&rtc0, &time_buf);
if (ret != 0) {
printf("get time error !\n");
return;
}

printf("current time is: %4d-%02d-%02d %02d:%02d:%02d\r\n",
time_buf.year, time_buf.month, time_buf.date,
time_buf.hr, time_buf.min, time_buf.sec);
}
else
{
printf("date argv error!plese retry!\r\n");
return;
}
}
else if(argc == 3)
{
if(strcmp(argv[0], "date"))
{
printf("cmd is error!plese retry!\r\n");
return ;
}

if(strcmp(argv[1], "-s") != 0)
{
printf("cmd is error!plese retry!\r\n");
return ;
}
else
{
//小时
ptimeIndex = strtok(argv[2], ":");
memcpy(s_Hours, ptimeIndex, strlen(ptimeIndex));
//分钟
ptimeIndex = strtok(NULL, ":");
memcpy(s_Minutes, ptimeIndex, strlen(ptimeIndex));
//秒
ptimeIndex = strtok(NULL, ":");
memcpy(s_Seconds, ptimeIndex, strlen(ptimeIndex));
//组合时间
time_buf.sec = atoi((const char*)s_Seconds);
time_buf.min = atoi((const char*)s_Minutes);
time_buf.hr = atoi((const char*)s_Hours);
time_buf.weekday = 6;
time_buf.date = 9;
time_buf.month = 12;
time_buf.year = 2023;

/* set rtc0 time to 2020/2/26,21:31:00 */
ret = hal_rtc_set_time(&rtc0, &time_buf);
if (ret != 0) {
printf("rtc0 set time error !\n");
return;
}
printf("set time is: %4d-%02d-%02d %02d:%02d:%02d\r\n", time_buf.year, time_buf.month,
time_buf.date, time_buf.hr, time_buf.min, time_buf.sec);
}
}
else
{
printf("input argument error!plese retry!\r\n");
date_help_show();
}
}

static void alarm_cmd(char *buf, int32_t len, int32_t argc, char **argv)
{
int ret = 0;
rtc_time_t time_buf = {0};
char *ptimeIndex = NULL;
char s_Hours[20] = {0};
char s_Minutes[20] = {0};
char s_Seconds[20] = {0};
uint32_t alarm_tick = 0;
if(argc == 2)
{
if(strcmp(argv[0], "alarm"))
{
printf("cmd is error!plese retry!\r\n");
return ;
}

if(strcmp(argv[1], "help") == 0)
{
date_help_show();
}
else if(strcmp(argv[1], "-r") == 0)
{
printf("alarm time is: %02d:%02d:%02d\r\n",
alarm_time.hours, alarm_time.minute, alarm_time.second);
}
else
{
printf("alarm argv error!plese retry!\r\n");
return;
}
}
else if(argc == 3)
{
if(strcmp(argv[0], "alarm"))
{
printf("cmd is error!plese retry!\r\n");
return ;
}

if(strcmp(argv[1], "-s") != 0)
{
printf("cmd is error!plese retry!\r\n");
return ;
}
else
{
//小时
ptimeIndex = strtok(argv[2], ":");
memcpy(s_Hours, ptimeIndex, strlen(ptimeIndex));
//分钟
ptimeIndex = strtok(NULL, ":");
memcpy(s_Minutes, ptimeIndex, strlen(ptimeIndex));
//秒
ptimeIndex = strtok(NULL, ":");
memcpy(s_Seconds, ptimeIndex, strlen(ptimeIndex));
//组合时间
alarm_time.second = atoi((const char*)s_Seconds);
alarm_time.minute = atoi((const char*)s_Minutes);
alarm_time.hours = atoi((const char*)s_Hours);

printf("alarm time set is %02d:%02d:%02d\r\n",
alarm_time.hours,alarm_time.minute,alarm_time.second);

alarm_tick = count_alarm_interval(alarm_time);

printf("alarm_tick=%d\r\n", alarm_tick);

if(pAlarmTimer == NULL)
{
pAlarmTimer = aos_malloc(sizeof(aos_timer_t));
if(pAlarmTimer)
{
ret = aos_timer_new(pAlarmTimer, timer1_func, NULL, alarm_tick, 1);
if (ret != 0)
{
LOGE(MODULE_NAME, "create timer error!");
return;
}
}
}
else
{
timer_time_change(alarm_tick);
printf("timer_time_change alarm_tick=%d\r\n", alarm_tick);
}

}
}
else
{
printf("input argument error!plese retry!\r\n");
alarm_help_show();
}
}

void cmd_init(void)
{
int ret;
static struct cli_command cmds[] = {
{"date","date read && set", date_cmd},
{"alarm","alarm read && set", alarm_cmd},
};

ret = aos_cli_register_commands(cmds, sizeof(cmds)/sizeof(cmds[0]));
if(ret != 0)
{
printf("cli register error!\r\n");
}
}

int application_start(int argc, char *argv[])
{
int ret = 0;
int index = 0;

led_init();

aos_set_log_level(AOS_LL_INFO);

aos_cli_init();
cmd_init();
hal_rtc_app_init();
while(1)
{
aos_msleep(1000);
hal_gpio_output_toggle(&led_gpio_dev[1]);
}

}

4. 测试结果

我们更新代码,设置好时间可以看到如下打印信息:

image-20231209130154049