赞
踩
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);
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);
注意,还有使用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() 定时超时执行一次函数
#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)
在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); */ }
上面函数里第50行:
usr_timer_add(NULL, adc_scan, 5, 0);//每隔5ms切换一次ADC扫描通道
把该句usr_timer注释掉,然后使用下面一句的sys_timer定时代替
sys_timer_add(NULL, adc_scan, 10);
此时测试你会发现系统根本无法进入低功耗状态,电流也在0.1ma-2ma左右。原因就是定时周期太短了,系统来不及进入低功耗,只好一直工作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。