赞
踩
测试SDK版本:《ac696n_soundbox_sdk_v1.6.0》
SDK给出了软件定时器的相关接口,主要有 sys_hi_timer_add、sys_s_hi_timer_add、sys_timer_add等。
列出AC696X系列软件定时器的相关知识点,再结合代码调试和工具测试,总结出使用案例。
上面的低功耗指的是 power down,不是soft poweroff。
usr_timer的强弱节拍指的是优先级的差异,使用高优先级定时器,系统无法进power down。使用低优先级定时器,系统可以进power down,但定时周期会被改变 。
sys_timer/usr_timer 与 sys_timerout/usr_timerout 接口区别在于 timeout 接口的回调只会被做一次,也就是设定一个未来的时间, 时间到了响应之后便结束这个定时器的生命周期。
usr_timer与sys_timer主要区别是,usr_timer是由硬件定时器提供时基, sys_timer是由systimer线程提供时基。
注册软件定时器不耗费硬件定时器,系统默认使用了 timer1 为系统 2ms 时钟定时用,所有的软件定时器都基于这个 timer1 拓展出来。
拓展出 2 种定时器使用方式(此知识点与实际应用有出入,但杰理各系列大致一样,这里只作为参考
):
1、在中断函数回调执行(切记不可调用延时或耗时等操作)
sys_hi_timer_add() 定时循环函数,会导致不进低功耗,直到主动删除
sys_hi_timeout_add() 定时超时执行一次函数
sys_s_hi_timer_add() 定时循环函数,不影响系统进低功耗,周期会变,建议使用此种定时器
sys_s_hi_timerout_add() 定时超时执行一次函数
注意点:此种定时器,注册的函数是在中断函数里面回调的,不可添加延时,或耗时的操作。 单位是 ms,但是是以 2ms 步进的。3ms 等同于 4ms 的。
2、在系统线程中执行,几乎可执行所有的操作
sys_timer_add() 定时循环函数,会影响下次进低功耗的时间点,周期太短会影响功耗。
sys_timeout_add() 定时超时执行一次函数
注意点:此种定时器,注册的函数是在线程执行的,优先级依赖于注册的线程的优先级。单位是 ms,但是是以 10ms 步进的。5ms 等同于 10ms 的。系统是以 10ms为系统滴答的。
强节拍:
#define sys_hi_timer_add(a, b, c)\
usr_timer_add(a, b, c, 1)
#define sys_hi_timer_modify(a, b)\
usr_timer_modify(a, b)
#define sys_hi_timer_del(a)\
usr_timer_del(a)
弱节拍:
#define sys_s_hi_timer_add(a, b, c)\
usr_timer_add(a, b, c, 0)
#define sys_s_hi_timer_modify(a, b)\
usr_timer_modify(a, b)
#define sys_s_hi_timer_del(a)\
usr_timer_del(a)
接口展开:
//*----------------------------------------------------------------------------*/ /**@brief usr_timer定时扫描增加接口 @param priv:私有参数 func:定时扫描回调函数 msec:定时时间, 单位:毫秒 priority:优先级,范围:0/1 @return 定时器分配的id号 @note 1、usr_timer的参数priority(优先级)为1,使用该类定时器,系统无法进入低功耗 2、usr_timer的参数priority(优先级)为0,使用该类定时器,系统低功耗会忽略该节拍,节拍不会丢失,但是周期会变 3、usr_timer属于异步接口, add的时候注册的扫描函数将在硬件定时器中时基到时候被调用。 4、对应释放接口usr_timer_del */ /*----------------------------------------------------------------------------*/ u16 usr_timer_add(void *priv, void (*func)(void *priv), u32 msec, u8 priority); //*----------------------------------------------------------------------------*/ /**@brief usr_timer修改定时扫描时间接口 @param id:usr_timer_add时分配的id号 msec:定时时间, 单位:毫秒 @return @note */ /*----------------------------------------------------------------------------*/ int usr_timer_modify(u16 id, u32 msec); //*----------------------------------------------------------------------------*/ /**@brief usr_timer删除接口 @param id:usr_timer_add时分配的id号 @return @note 注意与usr_timer_add成对使用 */ /*----------------------------------------------------------------------------*/ void usr_timer_del(u16 id);
强节拍:
#define sys_hi_timeout_add(a, b, c)\
usr_timeout_add(a, b, c, 1)
#define sys_hi_timeout_modify(a, b)\
usr_timeout_modify(a, b)
#define sys_hi_timeout_del(a)\
usr_timeout_del(a)
弱节拍:
#define sys_s_hi_timerout_add(a, b, c)\
usr_timeout_add(a, b, c, 0)
#define sys_s_hi_timeout_modify(a, b)\
usr_timeout_modify(a, b)
#define sys_s_hi_timeout_del(a)\
usr_timeout_del(a)
接口展开:
//*----------------------------------------------------------------------------*/ /**@brief usr_timer超时增加接口 @param priv:私有参数 func:超时回调函数 msec:定时时间, 单位:毫秒 priority:优先级,范围:0/1 @return 定时器分配的id号 @note 1、usr_timerout的参数priority(优先级)为1,使用该类定时器,系统无法进入低功耗 2、usr_timerout的参数priority(优先级)为0,使用该类定时器,系统低功耗会忽略该节拍,节拍不会丢失,但是周期会变 3、usr_timerout属于异步接口, add的时候注册的扫描函数将在硬件定时器中时基到时候被调用。 4、对应释放接口usr_timerout_del 4、timeout回调只会被执行一次 */ /*----------------------------------------------------------------------------*/ u16 usr_timeout_add(void *priv, void (*func)(void *priv), u32 msec, u8 priority); //*----------------------------------------------------------------------------*/ /**@brief usr_timerout修改超时时间接口 @param id:usr_timerout_add时分配的id号 msec:定时时间, 单位:毫秒 @return @note */ /*----------------------------------------------------------------------------*/ int usr_timeout_modify(u16 id, u32 msec); //*----------------------------------------------------------------------------*/ /**@brief usr_timeout删除接口 @param id:usr_timerout_add时分配的id号 @return @note 注意与usr_timerout_add成对使用 */ /*----------------------------------------------------------------------------*/ void usr_timeout_del(u16 id);
//*----------------------------------------------------------------------------*/ /**@brief sys_timer定时扫描增加接口 @param priv:私有参数 func:定时扫描回调函数 msec:定时时间, 单位:毫秒 @return 定时器分配的id号 @note 1、系统会进入低功耗,节拍不会丢失 2、sys_timer由systimer线程提供时基,属于同步接口, 也就是说在哪个线程add的sys_timer,定时时基到了 systimer线程会发事件通知对应的add线程响应(回调函数被执行) 3、与sys_timer_del成对使用 */ /*----------------------------------------------------------------------------*/ u16 sys_timer_add(void *priv, void (*func)(void *priv), u32 msec); //*----------------------------------------------------------------------------*/ /**@brief sys_timer定时扫描删除接口 @param id:sys_timer_add分配的id号 @return @note 1、与sys_timer_add成对使用 */ /*----------------------------------------------------------------------------*/ void sys_timer_del(u16);
//*----------------------------------------------------------------------------*/ /**@brief sys_timer超时增加接口 @param priv:私有参数 func:定时扫描回调函数 msec:定时时间, 单位:毫秒 @return 定时器分配的id号 @note 1、系统会进入低功耗,节拍不会丢失 2、sys_timerout由systimer线程提供时基,属于同步接口, 也就是说在哪个线程add的sys_timerout,定时时基到了 systimer线程会发事件通知对应的add线程响应(回调函数被执行) 3、timeout回调只会被执行一次 4、与sys_timerout_del成对使用 */ /*----------------------------------------------------------------------------*/ u16 sys_timeout_add(void *priv, void (*func)(void *priv), u32 msec); //*----------------------------------------------------------------------------*/ /**@brief sys_timer超时删除接口 @param id:sys_timerout_add分配的id号 @return @note 1、与sys_timerout_add成对使用 */ /*----------------------------------------------------------------------------*/ void sys_timeout_del(u16);
static u16 timer_loop = 0; static void timer_loop_func(void *priv) { static u16 cnt = 0; cnt++; printf("%s[cnt: %d]\n",__func__,cnt); if(cnt > 100){ if(timer_loop){ sys_timer_del(timer_loop);//删除前要判断 //sys_hi_timeout_del(timer_loop); //sys_s_hi_timer_del(timer_loop); timer_loop = 0;//删除后要清0 } cnt = 0; } } void timer_loop_init(void) { printf("%s[id: %d]\n",__func__,timer_loop); if(timer_loop){ sys_timer_del(timer_loop);//注册前,如果有注册过要del timer_loop = 0; } timer_loop = sys_timer_add(NULL, timer_loop_func, 100); //timer_loop = sys_hi_timer_add(NULL, timer_loop_func, 2); //timer_loop = sys_s_hi_timer_add(NULL, timer_loop_func, 10); }
static u16 timer_one = 0; static void timer_one_func(void *priv) { printf("%s\n", __func__); //sys_timeout_add注册的只会执行一次,底层会自动删除 //回调函数内不可调用sys_timeout_del timer_one = 0;//ID号清0,必须要有!!! } void timer_one_init(void) { printf("%s[id: %d]\n", __func__, timer_one); if (timer_one) { sys_timeout_del(timer_one);//注册前,如果有注册过要del timer_one = 0; } timer_one = sys_timeout_add(NULL, timer_one_func, 100); } void timer_one_del(void) { printf("%s[id: %d]\n", __func__, timer_one); if (timer_one) { sys_timeout_del(timer_one); timer_one = 0; } }
1、用软件定时器时,要注意看说明,有些定时器会被低功耗影响到周期,必要的时候可以关低功耗
#define TCFG_LOWPOWER_LOWPOWER_SEL 0//SLEEP_EN //SNIFF状态下芯片是否进入powerdown
2、分别用 sys_hi_timer_add、sys_s_hi_timer_add、sys_timer_add三种定时器类型注册循环定时器,定时参数最小可设置2ms,即使设置1ms,也是2ms执行一次回调函数,可见,usr_timer和sys_timer的时基应为2ms。
3、调整定时时间,测试发现,这三种软件定时器都是以2ms为步进的,但定时时间设为奇数时,比如3ms,发现并不像资料中描述的那样,设置3ms等同于4ms,而是有时2ms执行一次,有时4ms执行一次。定时时间设为2ms的倍数,则正常。
4、有些需求需要开机就跑一些定时器扫描任务的,注册定时器不能太靠前,建议放在下面的位置:
void app_main()
{
log_info("app_main\n");
app_var.start_time = timer_get_ms();
... ...
user_func_init();//用户功能初始化,注册软件定时器
... ...
app_task_loop();
}
5、AC696X系列SDK中有Usec Timer的接口,但是底层是没实现的,不可用。如果有微秒级的延时需求,比如一些单线控制的功放,微秒级的控制时序,杰理有提供硬件定时器实现的方法。
6、如果需要定时时间小于2ms的循环,切对精度要求高的,要使用硬件定时器中断,有必要的话,还要放到RAM中运行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。