首页 > 其他 > 详细

6. 休眠(电源管理)

时间:2020-11-04 10:11:56      阅读:49      评论:0      收藏:0      [点我收藏+]

  CC2530有3种睡眠模式,pm2模式比较省功耗而且可以被定时唤醒;pm3模式最省电但是只能被外部中断唤醒 。

1、sensordemo的sensor在入网以后,为什么灯在不断地闪? 其实,闪一次就是睡眠了一次:亮的时候睡过来,灭的时候睡下去。具体代码在halSleep函数里。要做的,就是读懂这个机制是怎么运作的。

2、为什么闪的频率那么高? zstack的睡眠机制就是在操作系统没事干的时候才睡眠,频率高说明应用程序让操作系统不断做事。你想让它长时间睡眠,那要做的就是不要不断地给操作系统事情做,找到分配系统任务的地方。

 

要设置低功耗模式,先确认:
1.f8wConfig.cfg文件中DRFD_RCVC_ALWAYS_ON定义为FALSE
2.Options->C/C++Compiler->Defined symbols中添加预编译“POWER_SAVING”;
重要函数void halSleep( uint16 osal_timeout )
1.首先将osal_timeout转成以320US为单位
2.获取下一次MAC定时器到期时间
3.  halPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER;  
//为PM2,PM3模式。 没有任务要执行就进入PM3深度睡眠,否则进入PM2睡眠,可以定时器唤醒。
4.唤醒

涉及文件
OSAL_PwrMgr.h       OSAL电源管理的API头文件
OSAL_PwrMgr.C      OSAL电源管理的API C文件
hal_sleep.c                底层的电源管理文件

电源管理结构体
typedef struct
{
  uint16 pwrmgr_task_state;                  //任务状态
  uint16 pwrmgr_next_timeout;             //下一次超时
  uint16 accumulated_sleep_time;        //睡眠时间
  uint8  pwrmgr_device;     //电源管理设备属性,有PWRMGR_ALWAYS_ON 和 PWRMGR_BATTERY两种
} pwrmgr_attribute_t;

/*********************************************************************
 * @brief   初始化电源管理函数,这个函数在OSAL.C里面的osal_init_system( )调用,
也就是在OSAL系统初始化的时候将电源管理模式调成了不会进入睡眠模式的状态。
 */
void osal_pwrmgr_init( void )
{
  pwrmgr_attribute.pwrmgr_device = PWRMGR_ALWAYS_ON; //默认没有睡眠模式
  pwrmgr_attribute.pwrmgr_task_state = 0;            //清零
}

/*********************************************************************
 * @fn      osal_pwrmgr_device
  * @brief   设置电源管理设备属性。
 * @param   pwrmgr_device -选择PWRMGR_ALWAYS_ON的话将不会进入睡眠模式,选择 PWRMGR_BATTERY将允许HAL管理CPU进入SLEEP LITE或者SLEEP DEEP状态。
*/
void osal_pwrmgr_device( uint8 pwrmgr_device )
{
  pwrmgr_attribute.pwrmgr_device = pwrmgr_device;
}

 /*  这个函数可以被每一个任务调用,用于设置这个任务是否支持低功耗运行,如果每一个任务不支持低功耗将无法进入低功耗模式运行。*/
uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state )
{
  if ( task_id >= tasksCnt )
    return ( INVALID_TASK );
  if ( state == PWRMGR_CONSERVE )
  {
    pwrmgr_attribute.pwrmgr_task_state &= ~(1 << task_id );    // 清零
  }
  else
  {  
    pwrmgr_attribute.pwrmgr_task_state |= (1 << task_id);     //置位
  }
  return ( SUCCESS );
}

#if defined( POWER_SAVING )
/*  osal_pwrmgr_powerconserve 这个函数在OSAL循环中如果没有任何事件需要执行的话将被调用,将设备进入 睡眠模式,不可以在其他地方调用该函数。需要打开POWER_SAVING的宏定义。*/
void osal_pwrmgr_powerconserve( void )
{
  uint16        next;
  halIntState_t  intState
  if ( pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON )   // 首先检查是否支持低功
  {
     if ( pwrmgr_attribute.pwrmgr_task_state == 0 )   //是否所有任务支持低功耗
    {
            HAL_ENTER_CRITICAL_SECTION( intState ); //关中断
            next = osal_next_timeout(); //查询软件定时器链表得到最近一次溢出时间
          HAL_EXIT_CRITICAL_SECTION( intState );   //开中断
          OSAL_SET_CPU_INTO_SLEEP( next );   //将系统进入睡眠模式
    }
  }
}
#endif /* POWER_SAVING */

加红部分是一个宏定义,在OnBoard.h里面定义的。
#define  OSAL_SET_CPU_INTO_SLEEP(timeout)  halSleep(timeout);
 
halSleep(timeout)是在hal_sleep.c中定义的。
这里面涉及的就是关于CC2530的电源管理寄存器的一些操作。具体可以看代码。

/* HAL电源管理模式是设置电源管理状态的,默认状态是HAL_SLEEP_OFF。其余设置均会关*闭系统时钟停止CPU。
 * HAL_SLEEP_TIMER模式可以被睡眠定时器中断和IO中断以及复位唤起。
 * HAL_SLEEP_DEEP模式可以被IO中断以及复位唤起。
 */
#define HAL_SLEEP_OFF         CC2530_PM0
#define HAL_SLEEP_TIMER       CC2530_PM2
#define HAL_SLEEP_DEEP        CC2530_PM3
 
#define CC2530_PM0            0 
#define CC2530_PM1            1 
#define CC2530_PM2            2 
#define CC2530_PM3            3 
 
#define MAX_SLEEP_TIME       510000 
最大睡眠时间是510000ms。

总结
可以看到在OSAL中是使用睡眠定时器来控制睡眠时间的,在系统初始化的时候是将电源控制结构体中的pwrmgr_device设备属性设置为PWRMGR_ALWAYS_ON,这样默认就不进入休眠状态。必须在应用层里面调用void osal_pwrmgr_device( uint8 pwrmgr_device )这个OSAL的API来设置使得OSAL能够进入休眠状态。
在用户任务中需要用的这样一个API——uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state )来设置这个任务是否支持休眠,如果有一个任务不支持休眠的话,整个系统就将不会进入休眠模式。这个在void osal_pwrmgr_powerconserve( void )中有相关的查询。
在OSAL的主循环中void osal_start_system( void )调用了osal_pwrmgr_powerconserve这个函数。

void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
  for(;;)  // Forever Loop
#endif
  {…… }
#if defined( POWER_SAVING )
    else  // Complete pass through all task events with no activity
    {
      osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
    }
#endif
  }
}

表示OSAL系统在检查完所有的任务事件之后发现没有事件需要处理,这样在POWER_SAVING宏定义打开的情况下将调用osal_pwrmgr_powerconserve();函数,在这函数中将会根据选择系统进入休眠。
 
退出休眠
当出现IO中断或者复位时候会退出休眠,或者在休眠定时器中断时候也将会退出休眠。如果是IO中断或者休眠定时器中断退出之后将回到进入休眠的地方继续向下执行,复位退出的话进入程序的初部分执行。

 

6. 休眠(电源管理)

原文:https://www.cnblogs.com/zeil/p/4285100.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!