Toggle navigation
首页
(current)
问答
文章
话题
商城
登录
注册
5、RDA8910CSDK二次开发:单次定时器和循环定时器
csdk
RDA8910
定时器
# 目录 [点击这里查看所有博文](https://blog.csdn.net/weixin_44570083/article/details/104285283) 本系列博客基于紫光展锐的`RDA8910 LTE Cat 1` bis芯片平台开发。理论...
# 目录 [点击这里查看所有博文](https://blog.csdn.net/weixin_44570083/article/details/104285283) 本系列博客所诉资料`均来自合宙官方`,并不是本人原创(只有博客是自己写的),csdk只是得到了`口头的允许公开授权`。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,`没有为自己谋取私利的想法`。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。 本系列博客基于紫光展锐的`RDA8910 LTE Cat 1` bis芯片平台开发。理论上适用于合宙的Air720U、Air724U、广和通L610以及安信可的cat-01模块。 先不管支不支持,如果你用的模块是是紫光展锐的RDA8910,那都不妨一试,也许会有意外收获(`也有可能变砖,慎重!!!`)。 我使用的是`Air724UG`开发板,如果在其他模块上不能用,那也不要强怼,也许是开发包不兼容吧。这里的代码是没有问题的。例程仅供参考! # 一、前言 ## 1.1、那么什么是定时器呢? 定时器通俗的讲就相当于一个闹钟。 我们的手机里面都有闹钟,每天早上负责叫醒我们上班不要迟到。只需要在手机里面设置好时间,然后可以按需选择每天都响,或者选择只响一次。作用是打断正在做的事(睡觉)。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200521174519482.png) 在单片机系统中也是有定时器的。而定时器又分为两种,分别是硬件定时器和软件定时器。 不管是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: 失败 **/ * BOOL `OPENAT_delete_timer`(HANDLE hTimer); ## 2.1、编写主程序 因为需要手动打开日志输出,在主程序中我选择在程序启动后让系统休眠一段时间,让我们不至于错过输出到日志信息。休眠时间到后会自动创建一个测试任务。 ```c //main函数 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`,系统会在合适的时间回收任务所占用的资源。 ```c 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); } //启动定时器1,为单次定时器 //单次定时器运行结束后,会自动停止并且删除定时器 BOOL err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); } //启动定时器2,为循环定时器 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的运行,并且回收定时器占用的资源。 ```c void timer_handle(void *pParameter) { BOOL err = 0; iot_debug_print(pParameter); if (strcmp(pParameter, "timer2") == 0) { timer2num += 1; switch (timer2num) { case 5://当定时器2进入5次后重新创建定时器1, //不创建会出现不能启动,证明了单次定时器运行结束会自动停止并删除 timer1 = OPENAT_create_timer(timer_handle, "timer1"); while (timer1 == NULL) { iot_debug_print("timer1 create FALSE"); osiThreadSleep(1000); } //启动定时器1,为单次定时器 err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); } break; case 10://当定时器2进入10次后停止并删除 /* 停止定时器接口 */ OPENAT_stop_timer(timer2); /* 删除定时器接口 */ OPENAT_delete_timer(timer2); break; default: break; } } } ``` # 三、编译并下载程序 完整代码在这,自取。 ```c /* * @Author: your name * @Date: 2020-05-19 14:05:32 * @LastEditTime: 2020-05-21 16:29:00 * @LastEditors: Please set LastEditors * @Description: In User Settings Edit * @FilePath: \RDA8910_CSDK\USER\user_main.c */ #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" //timer 软件定时器 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://当定时器2进入5次后重新创建定时器1, //不创建会出现不能启动,证明了单次定时器运行结束会自动停止并删除 timer1 = OPENAT_create_timer(timer_handle, "timer1"); while (timer1 == NULL) { iot_debug_print("timer1 create FALSE"); osiThreadSleep(1000); } //启动定时器1,为单次定时器 err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); } break; case 10://当定时器2进入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); } //启动定时器1,为单次定时器 //单次定时器运行结束后,会自动停止并且删除定时器 BOOL err = OPENAT_start_timer0(timer1, 1000 * 10); while (!err) { iot_debug_print("timer1 start FALSE"); osiThreadSleep(1000); } //启动定时器2,为循环定时器 err = OPENAT_loop_start_timer(timer2, 1000 * 2); while (!err) { iot_debug_print("timer2 start FALSE"); osiThreadSleep(1000); } //线程结束 osiThreadExit(); } //main函数 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秒,说明软件定时器精度不高,但是也可以凑合使用。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200521190253853.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU3MDA4Mw==,size_16,color_FFFFFF,t_70) > 不会下载的[点击这里](https://blog.csdn.net/weixin_44570083/article/details/104285283),进去查看我的`RDA8910 CSDK二次开发入门教程`专题第一篇博文`1、RDA8910CSDK二次开发:环境搭建`里面讲了怎么下载 > 这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束
发表于 2020-05-21 19:15
阅读 ( 1696 )
0 推荐
收藏
你可能感兴趣的文章
13、RDA8910CSDK二次开发:将你的代码藏起来----编译静态库
5385 浏览
1.1、RDA8910CSDK二次开发:CSDK极致开发体验
7714 浏览
12、RDA8910CSDK二次开发:c语言中最好用的JSON解析库---cJSON
6017 浏览
11、RDA8910CSDK二次开发:新鲜出炉的MQTT库
7852 浏览
10、RDA8910CSDK二次开发:简易的http通讯库
1805 浏览
9、RDA8910CSDK二次开发:趁热打铁干脆顺带把UDP通讯也给撸了吧
1844 浏览
相关问题
使用循环定时器操作和使用协程中间有没有区别?哪个效果会更好?
1 回答
0 条评论
请先
登录
后评论
陈夏
26 篇文章
作家榜
»
技术销售Delectate
43 文章
陈夏
26 文章
国梁
24 文章
miuser
21 文章
晨旭
20 文章
朱天华
19 文章
金艺
19 文章
杨奉武
18 文章
×
发送私信
发给:
内容:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!