目录
点击这里查看所有博文
本系列博客所诉资料均来自合宙官方
,并不是本人原创(只有博客是自己写的),csdk只是得到了口头的允许公开授权
。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法
。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。
本系列博客基于紫光展锐的RDA8910 LTE Cat 1
bis芯片平台开发。理论上适用于合宙的Air720U、Air724U、广和通L610以及安信可的cat-01模块。
先不管支不支持,如果你用的模块是是紫光展锐的RDA8910,那都不妨一试,也许会有意外收获(也有可能变砖,慎重!!!
)。
我使用的是Air724UG
开发板,如果在其他模块上不能用,那也不要强怼,也许是开发包不兼容吧。这里的代码是没有问题的。例程仅供参考!
一、前言
1.1、那么什么是定时器呢?
定时器通俗的讲就相当于一个闹钟。
我们的手机里面都有闹钟,每天早上负责叫醒我们上班不要迟到。只需要在手机里面设置好时间,然后可以按需选择每天都响,或者选择只响一次。作用是打断正在做的事(睡觉)。
在单片机系统中也是有定时器的。而定时器又分为两种,分别是硬件定时器和软件定时器。
不管是51系列、stm32系列、avr系列、亦或是其他的单片机,它们在裸机编程上都是拥有硬件定时器的,一般硬件定时器数量有几个到十几个不等,占用的是硬件资源。
- 硬件定时器:一般硬件定时器集成在CPU的内部,有的可以使用外置的硬件定时器芯片,其使用的时基是系统内部的高速时钟源经过分频得到的,高速时钟源又是由外部晶振倍频得到,精度非常高,但是依赖硬件,能使用的数量有限。
如果涉及到了操作系统编程,软件定时器那就必不可少。
- 软件定时器:一般软件定时器都是利用的是操作系统的延时阻塞性,在定时器启动和触发时记录下当前的系统时间,每隔一个时间片去查询下有没有到指定的定时时间,有的话就触发软件回调,精度相对硬件定时器要差得多,理论上是没有使用数量限制的,内存有多大,定时器就可以有多少。
二、编写测试程序
RDA8910的CSDK并非是采用裸机编程,而是采用实时操作系统框架编程,上面前言说了既然涉及到了RTOS那sdk里面一般都会提供了软件定时器,那我们何不一起来看看呢。
使用定时器的驱动需要包含#include "am_openat.h""
头文件,我们这里只用到了五个函数,分别是:
/*创建定时器
*@param pFunc: 定时回调函数
*@param pParameter: 作为参数传递给定时器到时处理函数
*@return HANDLE:定时器句柄
*/
HANDLE OPENAT_create_timer
( PTIMER_EXPFUNC pFunc,PVOID pParameter);
/**启动单次运行定时器
*@param hTimer: 定时器句柄,create_timer接口返回值
*@param nMillisecondes: 定时器时间
*@return TRUE: 成功
FALSE: 失败
*/
BOOL OPENAT_start_timer0
( HANDLE hTimer,UINT32 nMillisecondes);
/*启动循环运行定时器
*@param hTimer: 定时器句柄,create_timer接口返回值
*@param nMillisecondes: 定时器时间
*@return TRUE: 成功
FALSE: 失败
*/
- BOOL
OPENAT_loop_start_timer
( HANDLE hTimer,UINT32 nMillisecondes);
/**停止定时器
@param hTimer: 定时器句柄,create_timer接口返回值
*@return TRUE: 成功
FALSE: 失败
*/
- BOOL
OPENAT_stop_timer
(HANDLE hTimer );
/**删除定时器
@param hTimer: 定时器句柄,create_timer接口返回值
*@return TRUE: 成功
FALSE: 失败
*/
因为需要手动打开日志输出,在主程序中我选择在程序启动后让系统休眠一段时间,让我们不至于错过输出到日志信息。休眠时间到后会自动创建一个测试任务。
1 2 3 4 5 6 7 8 9
| int appimg_enter(void *param) { iot_os_sleep(10000); osiThreadCreate("TestTask", TestTask, NULL, OSI_PRIORITY_NORMAL, 2048, 0); return 0; }
|
2.2、编写测试任务
在测试任务中,这里创建了两个定时器,一个是单次运行定时器,一个是循环定时器。
多个定时器可以公用一个定时回调函数通过创建定时器时传入的参数区分当前触发的中断是定时器几,也可以使用多个回调函数。
创建完成之后分别调用启动单次定时器函数OPENAT_start_timer0
,和启动循环定时器函数OPENAT_loop_start_timer
让定时器开始运行
创建完成之后调用线程离开函数osiThreadExit
,系统会在合适的时间回收任务所占用的资源。
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
| static void TestTask(void *param) { timer1 = OPENAT_create_timer(timer_handle, "timer1"); while (timer1 == NULL) { iot_debug_print("timer1 create FALSE"); osiThreadSleep(1000); }
timer2 = OPENAT_create_timer(timer_handle, "timer2"); while (timer2 == NULL) { iot_debug_print("timer2 create FALSE"); osiThreadSleep(1000); }
BOOL err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); }
err = OPENAT_loop_start_timer(timer2, 1000 * 2); while (!err) { iot_debug_print("timer2 start FALSE"); osiThreadSleep(1000); } osiThreadExit(); }
|
2.3、编写定时回调函数
在定时回调函数里面我们选择在定时器2进入中断5次后,重新创建并启动定时器1。我这里做过测试,如果不重新创建定时器1,直接启动会启动失败,那就说明一个问题单次运行定时器在触发一次回调后会自动退出定时器线程并且回收定时器资源。
当定时器2进入10次回调函数,选择停止定时器2的运行,并且回收定时器占用的资源。
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
| void timer_handle(void *pParameter) { BOOL err = 0; iot_debug_print(pParameter); if (strcmp(pParameter, "timer2") == 0) { timer2num += 1; switch (timer2num) { case 5: timer1 = OPENAT_create_timer(timer_handle, "timer1"); while (timer1 == NULL) { iot_debug_print("timer1 create FALSE"); osiThreadSleep(1000); } err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); } break; case 10: OPENAT_stop_timer(timer2); OPENAT_delete_timer(timer2); break; default: break; } } }
|
三、编译并下载程序
完整代码在这,自取。
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
|
#include "string.h" #include "cs_types.h"
#include "osi_log.h" #include "osi_api.h"
#include "am_openat.h" #include "am_openat_vat.h" #include "am_openat_common.h"
#include "iot_debug.h" #include "iot_uart.h" #include "iot_os.h" #include "iot_gpio.h" #include "iot_pmd.h" #include "iot_adc.h" #include "iot_vat.h"
HANDLE timer1 = NULL, timer2 = NULL; uint8 timer2num = 0; void timer_handle(void *pParameter) { BOOL err = 0; iot_debug_print(pParameter); if (strcmp(pParameter, "timer2") == 0) { timer2num += 1; switch (timer2num) { case 5: timer1 = OPENAT_create_timer(timer_handle, "timer1"); while (timer1 == NULL) { iot_debug_print("timer1 create FALSE"); osiThreadSleep(1000); } err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); } break; case 10: OPENAT_stop_timer(timer2); OPENAT_delete_timer(timer2); break; default: break; } } }
static void TestTask(void *param) { timer1 = OPENAT_create_timer(timer_handle, "timer1"); while (timer1 == NULL) { iot_debug_print("timer1 create FALSE"); osiThreadSleep(1000); }
timer2 = OPENAT_create_timer(timer_handle, "timer2"); while (timer2 == NULL) { iot_debug_print("timer2 create FALSE"); osiThreadSleep(1000); }
BOOL err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); }
err = OPENAT_loop_start_timer(timer2, 1000 * 2); while (!err) { iot_debug_print("timer2 start FALSE"); osiThreadSleep(1000); } osiThreadExit(); }
int appimg_enter(void *param) { iot_os_sleep(10000); osiThreadCreate("TestTask", TestTask, NULL, OSI_PRIORITY_NORMAL, 2048, 0); return 0; }
void appimg_exit(void) { OSI_LOGI(0, "application image exit"); }
|
查看输出,定时器1一共进入了2次中断。定时器2一共进入了10次中断,验证了程序运行是正确的。通过输出的时间戳也可以发现,定时器2连续两次进入回调其中间隔的时间并不是严格的2秒,说明软件定时器精度不高,但是也可以凑合使用。
不会下载的点击这里,进去查看我的RDA8910 CSDK二次开发入门教程
专题第一篇博文1、RDA8910CSDK二次开发:环境搭建
里面讲了怎么下载
这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束