当前位置:   article > 正文

杰理AC632定时任务接口sys_timer_add和usr_timer_add区别详述

sys_timer_add
1. sys_timer

sys_timer源自timer1 的 1ms 时钟定时。sys_timer是软件定时器,注册的函数是在线程执行的,优先级依赖于注册的线程的优先级。
sys_timer在系统线程中执行, 几乎可执行所有的操作。
sys_timer允许系统进入低功耗,但是定时时间到了会唤醒系统处理任务。另外,sys_timer_add() 定时循环函数,会影响下次进低功耗的时间点,如果周期太短会影响功耗。
sys_timer单位是 ms,但是是以 10ms 步进的。如果设置5ms,结果是 等同于 10ms 的。sys_timer是以 10ms 为系统滴答的。

所以,当定时参数设置的比较小时(比如10ms),系统基本不会进入低功耗,此时测试芯片电流大约100uA以上甚至更高,正常睡眠状态电流20uA。所以使用时必须避免此类情况发生。

/**
 * @brief 添加ms级系统非timeout类型定时任务。
 *
 * @param [in] priv 定时任务处理函数的输入参数
 * @param [in] func 定时任务处理函数
 * @param [in] 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 删除ms级非timeout类型定时任务。
 *
 * @param [in] id 要删除的任务ID
 *
 * @note
 * 1、与sys_timer_add成对使用。
 */
void sys_timer_del(u16);

/**
 * @brief 添加ms级系统timeout类型定时任务。
 *
 * @param [in] priv 定时任务处理函数的输入参数
 * @param [in] func 定时任务处理函数
 * @param [in] msec 定时时间
 *
 * @return 定时器分配的id号
 *
 * @note
 * 1、系统会进入低功耗,节拍不会丢失,定时结束会唤醒系统;
 * 2、sys_timeout由systimer线程提供时基,属于同步接口,
 *    也就是说在哪个线程add的sys_timeout,定时时基到了
 *    systimer线程会发事件通知对应的add线程响应(回调函数被执行);
 * 3、timeout回调只会被执行一次;
 * 4、与sys_timerout_del成对使用。
 */
u16 sys_timeout_add(void *priv, void (*func)(void *priv), u32 msec);

/**
 * @brief 删除ms级timeout类型定时任务。
 *
 * @param [in] id 要删除的任务ID
 *
 * @note
 * 1、与sys_timerout_add成对使用。
 */
void sys_timeout_del(u16);

/**
 * @brief 重置ms级定时任务定时时间。
 *
 * @param [in] id 要修改的任务ID
 *
 * @note
 * 1、重置之后重新计时。
 */
void sys_timer_re_run(u16 id);

/**
 * @brief 修改ms级定时任务处理函数的输入参数。
 *
 * @param [in] id 要修改的任务ID
 * @param [in] priv 处理函数的输入参数
 */
void sys_timer_set_user_data(u16 id, void *priv);

/**
 * @brief 获取ms级定时任务处理函数的输入参数的值。
 *
 * @param [in] id 要获取处理函数的输入参数值的任务ID
 *
 * @return 返回add时的私有参数
 *
 * @note
 * 1、如果有通过sys_timer_set_user_data重新设置私有参数,
 *    则返回的是设置后的私有参数。
 */
void *sys_timer_get_user_data(u16 id);

/*-----------------------------------------------------------*/

/*
 *  System Usec Timer
 */
int sys_timer_modify(u16 id, u32 msec);

int sys_usec_timer_add(void *priv, void (*func)(void *priv), u32 usec);

void sys_usec_timer_schedule(struct sys_cpu_timer *);

void sys_usec_timer_set(int _t, u32 usec);

void sys_usec_timer_del(int);

void sys_timer_dump_time(void);

u32 sys_timer_get_ms(void);

  • 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
2. user_timer

usr_timer是增加硬件定时器。如果优先级取1,则芯片不会进入低功耗。如果优先级取0,芯片可以进入低功耗,但此时定时周期会变(可能多加了睡眠时间)。
所以,如果用了user_timer,那就难免不准。误差是由于芯片进入低功耗造成的,这是不可避免的。

此种定时器,注册的函数是在中断函数里面回调的,不可添加延时,或耗时的操作。
user_timer单位是 ms, 是以 1ms 步进的。

/**
 * @brief usr_timer定时扫描增加接口
 *
 * @param [in] priv 私有参数
 * @param [in] func 定时扫描回调函数
 * @param [in] msec 定时时间, 单位:毫秒
 * @param [in] 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 [in] priv 私有参数
 * @param [in] func 超时回调函数
 * @param [in] msec 定时时间, 单位:毫秒
 * @param [in] priority 优先级,范围:0/1
 *
 * @return 定时器分配的id号
 *
 * @note
 * 1、usr_timerout的参数priority(优先级)为1,使用该类定时器,系统无法进入低功耗;
 * 2、usr_timerout的参数priority(优先级)为0,使用该类定时器,系统低功耗会忽略该节拍,节拍不会丢失,但是定时周期会变;
 * 3、usr_timerout属于异步接口, add的时候注册的扫描函数将在硬件定时器中时基到时候被调用;
 * 4、对应释放接口usr_timerout_del;
 * 5、timeout回调只会被执行一次。
*/
u16 usr_timeout_add(void *priv, void (*func)(void *priv), u32 msec, u8 priority);

/**
 * @brief usr_timer修改定时扫描时间接口
 *
 * @param [in] id usr_timer_add时分配的id号
 * @param [in] msec 定时时间,单位:毫秒
*/
int usr_timer_modify(u16 id, u32 msec);

/**
 * @brief usr_timerout修改超时时间接口
 *
 * @param [in] id usr_timerout_add时分配的id号
 * @param [in] msec 定时时间,单位:毫秒
*/
int usr_timeout_modify(u16 id, u32 msec);

/**
 * @brief usr_timer删除接口
 *
 * @param [in] id usr_timer_add时分配的id号
 *
 * @note
 * 1、注意与usr_timer_add成对使用。
*/
void usr_timer_del(u16 id);

/**
 * @brief usr_timeout删除接口
 *
 * @param [in] id usr_timerout_add时分配的id号
 *
 * @note
 * 1、注意与usr_timerout_add成对使用。
*/
void usr_timeout_del(u16 id);

/**
 * @brief usr_time输出调试信息
 *
 * @note
 * 1.调试时可用;
 * 2.将输出所有被add定时器的id及其时间(msec)。
*/
void usr_timer_dump(void);

  • 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

注意,还有使用sys_hi_timer接口的,其实在time.h文件里已经预定义了,sys_hi_timer等于user_timer。

sys_hi_timer_add() 定时循环函数,会导致不进低功耗,直到主动删除
sys_hi_timeout_add() 定时超时执行一次函数
sys_s_hi_timer_add() 定时循环函数,不影响系统进低功耗,周期会变,建议使用此种定时器
sys_s_hi_timerout_add() 定时超时执行一次函数

  • 1
  • 2
  • 3
  • 4
  • 5
#define sys_hi_timer_schedule()\
    usr_timer_schedule()

#define sys_hi_timer_add(a, b, c)\
    usr_timer_add(a, b, c, 1)

#define sys_hi_timeout_add(a, b, c)\
    usr_timeout_add(a, b, c, 1)

#define sys_hi_timer_modify(a, b)\
    usr_timer_modify(a, b)

#define sys_hi_timeout_modify(a, b)\
    usr_timeout_modify(a, b)

#define sys_hi_timer_del(a)\
    usr_timer_del(a)

#define sys_hi_timeout_del(a)\
    usr_timeout_del(a)

#define sys_s_hi_timer_add(a, b, c)\
    usr_timer_add(a, b, c, 0)

#define sys_s_hi_timerout_add(a, b, c)\
    usr_timeout_add(a, b, c, 0)

#define sys_s_hi_timer_modify(a, b)\
    usr_timer_modify(a, b)

#define sys_s_hi_timeout_modify(a, b)\
    usr_timeout_modify(a, b)

#define sys_s_hi_timer_del(a)\
    usr_timer_del(a)

#define sys_s_hi_timeout_del(a)\
    usr_timeout_del(a)
  • 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
3. 两类定时器测试

在adc_api.c文件里找到void _adc_init(u32 sys_lvd_en)函数。该函数是ADC功能初始化的函数。在其末尾添加了一个定时扫描任务void adc_scan(void *priv)。原来代码如下:

void _adc_init(u32 sys_lvd_en)
{
    memset(adc_queue, 0xff, sizeof(adc_queue));
    memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
    memset(vbat_value_array, 0x0, sizeof(vbat_value_array));

    JL_ADC->CON = 0;

    adc_add_sample_ch(AD_CH_LDOREF);
    adc_set_sample_freq(AD_CH_LDOREF, PMU_CH_SAMPLE_FREQ);

    adc_add_sample_ch(AD_CH_VBAT);
    adc_set_sample_freq(AD_CH_VBAT, PMU_CH_SAMPLE_FREQ);

    adc_add_sample_ch(AD_CH_DTEMP);
    adc_set_sample_freq(AD_CH_DTEMP, PMU_CH_SAMPLE_FREQ);

    u32 sum_ad = 0;
    adc_sample(AD_CH_LDOREF);
    for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
        sum_ad += adc_wait_pnd();
    }
    sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
    adc_value_push(vbg_value_array, sum_ad);
    printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));

    sum_ad = 0;
    adc_sample(AD_CH_VBAT);
    for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
        sum_ad += adc_wait_pnd();
    }
    sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
    adc_value_push(vbat_value_array, sum_ad);
    printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
    printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);

    sum_ad = 0;
    adc_sample(AD_CH_DTEMP);
    for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
        sum_ad += adc_wait_pnd();
    }
    sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
    dtemp_voltage = adc_value_to_voltage(adc_value_avg(vbg_value_array), sum_ad);
    printf("dtemp_adc_value = %d\n", sum_ad);
    printf("dtemp = %d mv\n", dtemp_voltage);


    request_irq(IRQ_SARADC_IDX, 0, adc_isr, 0);

    usr_timer_add(NULL, adc_scan, 5, 0); //2ms
    /* sys_timer_add(NULL, adc_scan, 10); //2ms */

    /* void adc_test();                              */
    /* usr_timer_add(NULL, adc_test, 1000, 0); //2ms */

    /* extern void wdt_close(); */
    /* wdt_close(); */
    /*  */
    /* while(1); */
}

  • 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

上面函数里第50行:

usr_timer_add(NULL, adc_scan, 5, 0);//每隔5ms切换一次ADC扫描通道
  • 1

把该句usr_timer注释掉,然后使用下面一句的sys_timer定时代替

sys_timer_add(NULL, adc_scan, 10);
  • 1

此时测试你会发现系统根本无法进入低功耗状态,电流也在0.1ma-2ma左右。原因就是定时周期太短了,系统来不及进入低功耗,只好一直工作。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/314510
推荐阅读
  

闽ICP备14008679号