【杰理AC696X】软件定时器介绍

【杰理AC696X】软件定时器介绍

测试SDK版本:《ac696n_soundbox_sdk_v1.6.0》



前言

SDK给出了软件定时器的相关接口,主要有 sys_hi_timer_add、sys_s_hi_timer_add、sys_timer_add等。
列出AC696X系列软件定时器的相关知识点,再结合代码调试和工具测试,总结出使用案例。


一、功能概述

1.1 软件定时器类型

在这里插入图片描述


1.2 软件定时器相关知识

  • 上面的低功耗指的是 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为系统滴答的。

二、流程框架

2.1 usr_timer 流程框架

在这里插入图片描述


2.1 sys_timer 流程框架

在这里插入图片描述


三、接口详细说明

3.1 usr_timer定时循环接口

强节拍:

#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);

3.2 usr_timer定时超时接口

强节拍:

#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);

3.3 sys_timer定时循环接口

//*----------------------------------------------------------------------------*/
/**@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);

3.4 sys_timer定时超时接口

//*----------------------------------------------------------------------------*/
/**@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);

四、使用示例

4.1 循环定时器写法

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);
}

4.2 延时定时器写法

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中运行。

### 回答1: 在杰里ac69中,定时器被用来唤醒单片机,实现了单片机的定时功能。当我们需要单片机在特定的时间间隔后执行某个任务时,可以设置定时器来精确地计时,达到定时唤醒的目的。 杰里ac69中的定时器一般由寄存器控制,我们可以通过设置寄存器的值来调整定时器的工作频率和计时周期。在设定好定时器的计时周期后,单片机将会进入休眠状态,等待定时器计时完成后被唤醒。 具体的工作流程如下:首先,我们需要设置定时器的计时周期,这可以通过设置定时器的控制寄存器来实现。控制寄存器中包括了定时器的使能、计时模式、计时周期等参数的设置。我们可以根据要求设定合适的值。 然后,启动定时器,使其开始计时。当定时器开始计时后,单片机将进入休眠状态,等待定时器计时完成。 当定时器计时完成后,触发定时器中断。单片机被唤醒,并执行与该定时器相关的任务。 需要注意的是,为了保证定时器正常工作,我们需要在编程中合理处理定时器中断,并且根据具体需求来设置定时器的计时周期。 总结起来,杰里ac69中的定时器通过设置寄存器的值来调整计时周期,实现了单片机的定时唤醒功能。这种定时器可以在单片机休眠状态下准确计时,并在计时完成后唤醒单片机执行相应的任务。 ### 回答2: 杰里ac69中的定时器是一种用来控制单片机工作时间的装置。定时器可以设置一个特定的时间间隔,在达到设定的时间后,会发出一个信号来唤醒单片机。这个信号一般是一个中断信号,能够打断单片机当前的工作状态,使其执行预设好的中断服务程序。 在使用杰里ac69中的定时器唤醒单片机时,首先需要设置定时器的工作模式和计数值。工作模式可以根据需求选择不同的计时方式,比如定时、计时器或脉冲计数等。计数值则决定了定时器的溢出时间,即在多久后触发中断。 当定时器开始工作后,单片机会根据定时器的计时值进行计数。当计数值达到设定的阈值时,定时器会自动触发中断,并将一个中断请求发送给单片机单片机接收到中断请求后,会立即中断当前的工作,跳转到预设好的中断服务程序中执行。 在中断服务程序中,可以编写相应的代码来执行特定的功能或任务。比如在定时器中断时,可以进行数据存储、状态更新、信号输出等操作。执行完中断服务程序后,单片机会返回到之前的工作程序中,继续执行之前的任务。 总之,杰里ac69中的定时器通过设置特定的时间间隔和中断服务程序,实现了定时唤醒单片机的功能。这种定时唤醒方式可以广泛应用于各类电子设备中,使其能够按照设定的时间间隔自动执行特定的任务。 ### 回答3: 杰里ac69中的定时器可以通过设置特定的时间间隔来唤醒单片机定时器通常由一个定时器计数器和相关的控制寄存器组成。在单片机中,我们可以使用定时器来实现定时中断,通过设置一个特定的时间值,当定时器计数器计数到该值时,就会触发定时中断,进而唤醒单片机。 要实现定时器唤醒单片机,需要进行以下步骤: 1. 初始化定时器:使用单片机的相关寄存器配置定时器的工作模式、计数范围和时钟源等参数。 2. 设置定时中断时间值:根据需要设置一个特定的时间间隔,将该值写入定时器的计数寄存器。单片机会自动开始计数,并在计数值达到所设置的时间值时触发定时中断。 3. 配置中断控制器:使能定时中断,并设置中断优先级。 4. 运行单片机程序:在程序运行过程中,在定时器计数到设定的时间值时,会触发定时中断,进而唤醒单片机执行中断服务程序。 5. 中断服务程序:在中断服务程序中,可以执行需要在定时器中断触发时所需的操作,例如更新相关变量、发送数据或执行其他任务。 通过上述步骤,杰里ac69中的定时器可以唤醒单片机,实现定时中断。这对于需要按照一定时间间隔进行任务处理的应用场景非常有用,如周期性传输数据、定时任务等。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值