Zigbee节点只有终端设备类型可以设置休眠模式,要设置休眠模式,在配置上先要确保:

1.f8wConfig.cfg文件中DRFD_RCVC_ALWAYS_ON定义为FALSE;

/***************************************** The following are for End Devices only***************************************/-DRFD_RCVC_ALWAYS_ON=FALSE

2.在IAR的工程Options->C/C++Compiler->Preprocessor->Defined symbols中预编译POWER_SAVING;

除此之外,设备在运行过程中进入睡眠模式需要满足:

1.电源管理设备属性为PWRMGR_BATTERY;

2.所有任务都支持低功耗;

3.当前无事件需要处理;

满足以上条件后终端设备将进入睡眠状态。第三个条件实际上也暗示了终端设备的唤醒条件,进入睡眠模式需要保证当前无事件处理,假如在睡眠之前存在定时触发事件,那么当这个定时时间到后事件被设置,终端设备就要被唤醒去处理这个事件,这种机制也决定了Zigbee睡眠时间的长短是由事件的调度所决定的。

那Zigbee OSAL到底是怎样管理睡眠的呢?从ZMain.c中的main()函数中进入OSAL的主循环osal_start_system(),程序会在这个函数中一遍又一遍地轮询是否有事件需要处理,每次轮询时,当没有事件需要处理时并且定义了POWER_SAVING时则会调用osal_pwrmgr_powerconserve()考虑是否进入睡眠模式。

进入osal_pwrmgr_powerconserve()

发现这个函数可以调用 OSAL_SET_CPU_INTO_SLEEP( next )使设备进入睡眠模式,但需要满足两个条件:

1.pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON;

2. pwrmgr_attribute.pwrmgr_task_state == 0

两个条件都涉及了一个pwrmgr_attribute_t类型的全局变量pwrmgr_attribute,这个变量是用于电源管理的。

/* This global variable stores the power management attributes.*/
pwrmgr_attribute_t pwrmgr_attribute;
/* These attributes define sleep beheaver. The attributes can be changed* for each sleep cycle or when the device characteristic change.*/
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;      

pwrmgr_attribute中包含了四个元素,pwrmgr_task_state记录了是否所有任务都支持低功耗,pwrmgr_device则是电源管理的设备属性,这两个正对应了最开始提到的设备要成功进入睡眠状态必须要满足的三个条件中的前两个:

1.电源管理设备属性为PWRMGR_BATTERY;

2.所有任务都支持低功耗;

3.当前无事件需要处理;

pwrmgr_sleep_time顾名思义是睡眠时间,pwrmgr_next_timeout是下次超时时间。

至此,显然如果不能同时满足pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON和pwrmgr_attribute.pwrmgr_task_state == 0是无法调用 OSAL_SET_CPU_INTO_SLEEP( next )从而使设备进入睡眠模式的,那么全局变量pwrmgr_attribute在哪里进行了初始化呢?

进入ZMain()中main()函数的osal_init_system()发现有一个初始化电源配置的函数osal_pwrmgr_init()

uint8 osal_init_system( void )
{// Initialize the Memory Allocation Systemosal_mem_init();// Initialize the message queueosal_qHead = NULL;// Initialize the timersosalTimerInit();// Initialize the Power Management Systemosal_pwrmgr_init();// Initialize the system tasks.osalInitTasks();// Setup efficient search for the first free block of heap.osal_mem_kick();return ( SUCCESS );
}

osal_pwrmgr_init()初始化了pwrmgr_attribute的两个元素

void osal_pwrmgr_init( void )
{pwrmgr_attribute.pwrmgr_device = PWRMGR_ALWAYS_ON; // Default to no power conservation.pwrmgr_attribute.pwrmgr_task_state = 0;            // Cleared.  All set to conserve
}

由于初始化pwrmgr_device = PWRMGR_ALWAYS_ON ,显然默认情况下是不支持进入睡眠模式的。好在pwrmgr_attribute是以全局变量的形式定义的,所以我们可以在应用层直接更改pwrmgr_device使其为PWRMGR_BATTERY。在OSAL_PwrMgr.c设置了可以直接更改pwrmgr_device的函数 osal_pwrmgr_device(),所以也可以通过在应用层调用osal_pwrmgr_device( PWRMGR_BATTERY )将电源管理设备属性更改为PWRMGR_BATTERY。

void osal_pwrmgr_device( uint8 pwrmgr_device )
{pwrmgr_attribute.pwrmgr_device = pwrmgr_device;
}

OSAL.c中还定义了osal_pwrmgr_task_state( uint8 task_id, uint8 state ),该函数可以被任何任务调用来标记自己是否支持低功耗,支持则为PWRMGR_CONSERVE,不支持则为PWRMGR_HOLD。

#define PWRMGR_CONSERVE 0
#define PWRMGR_HOLD     1
/********************************************************************** @fn      osal_pwrmgr_task_state** @brief   This function is called by each task to state whether or*          not this task wants to conserve power.** @param   task_id - calling task ID.*          state - whether the calling task wants to*          conserve power or not.** @return  SUCCESS if task complete*/
uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state )
{if ( task_id >= tasksCnt )return ( INVALID_TASK );if ( state == PWRMGR_CONSERVE ){// Clear the task state flagpwrmgr_attribute.pwrmgr_task_state &= ~(1 << task_id );}else{// Set the task state flagpwrmgr_attribute.pwrmgr_task_state |= (1 << task_id);}return ( SUCCESS );
}

回到OSAL_PwrMgr.c中的osal_pwrmgr_powerconserve(),当在应用层更改pwemgr_device为PWRMGR_BATTERY后且所有任务皆支持低功耗后,即满足

1.pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON;

2. pwrmgr_attribute.pwrmgr_task_state == 0

void osal_pwrmgr_powerconserve( void )
{uint16        next;halIntState_t intState;// Should we even look into power conservationif ( pwrmgr_attribute.pwrmgr_device != PWRMGR_ALWAYS_ON ){// Are all tasks in agreement to conserveif ( pwrmgr_attribute.pwrmgr_task_state == 0 ){// Hold off interrupts.HAL_ENTER_CRITICAL_SECTION( intState );// Get next time-outnext = osal_next_timeout();// Re-enable interrupts.HAL_EXIT_CRITICAL_SECTION( intState );// Put the processor into sleep modeOSAL_SET_CPU_INTO_SLEEP( next );}}
}

将调用 OSAL_SET_CPU_INTO_SLEEP( next ),OSAL_SET_CPU_INTO_SLEEP是宏,这里实际上就是调用halSleep(next),halSleep(next)中描述了设备睡眠的相关配置。

#define OSAL_SET_CPU_INTO_SLEEP(timeout) halSleep(timeout); /* Called from OSAL_PwrMgr */
void halSleep( uint16 osal_timeout )
{uint32        timeout;uint32        macTimeout = 0;halAccumulatedSleepTime = 0;/* get next OSAL timer expiration converted to 320 usec units */timeout = HAL_SLEEP_MS_TO_320US(osal_timeout);if (timeout == 0){timeout = MAC_PwrNextTimeout();}else{/* get next MAC timer expiration */macTimeout = MAC_PwrNextTimeout();/* get lesser of two timeouts */if ((macTimeout != 0) && (macTimeout < timeout)){timeout = macTimeout;}}/* HAL_SLEEP_PM2 is entered only if the timeout is zero and* the device is a stimulated device.*/halPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER;/* DEEP sleep can only be entered when zgPollRate == 0.* This is to eliminate any possibility of entering PM3 between* two network timers.*/
#if ZG_BUILD_ENDDEVICE_TYPE && defined (NWK_AUTO_POLL)if ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) ||(timeout == 0 && zgPollRate == 0))
#elseif ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) ||(timeout == 0))
#endif{halIntState_t ien0, ien1, ien2;HAL_ASSERT(HAL_INTERRUPTS_ARE_ENABLED());HAL_DISABLE_INTERRUPTS();/* always use "deep sleep" to turn off radio VREG on CC2530 */if (MAC_PwrOffReq(MAC_PWR_SLEEP_DEEP) == MAC_SUCCESS){
#if ((defined HAL_KEY) && (HAL_KEY == TRUE))/* get peripherals ready for sleep */HalKeyEnterSleep();
#endif#ifdef HAL_SLEEP_DEBUG_LEDHAL_TURN_OFF_LED3();
#else/* use this to turn LEDs off during sleep */HalLedEnterSleep();
#endif/* enable sleep timer interrupt */if (timeout != 0){if (timeout > HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME )){timeout -= HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME );halSleepSetTimer(HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME ));}else{/* set sleep timer */halSleepSetTimer(timeout);}/* set up sleep timer interrupt */HAL_SLEEP_TIMER_CLEAR_INT();HAL_SLEEP_TIMER_ENABLE_INT();}#ifdef HAL_SLEEP_DEBUG_LEDif (halPwrMgtMode == CC2530_PM1){HAL_TURN_ON_LED1();}else{HAL_TURN_OFF_LED1();}
#endif/* save interrupt enable registers and disable all interrupts */HAL_SLEEP_IE_BACKUP_AND_DISABLE(ien0, ien1, ien2);HAL_ENABLE_INTERRUPTS();/* set CC2530 power mode, interrupt is disabled after this function */HAL_SLEEP_SET_POWER_MODE(halPwrMgtMode);/* the interrupt is disabled - see halSetSleepMode() *//* restore interrupt enable registers */HAL_SLEEP_IE_RESTORE(ien0, ien1, ien2);/* disable sleep timer interrupt */HAL_SLEEP_TIMER_DISABLE_INT();/* Calculate timer elasped */halAccumulatedSleepTime += (HalTimerElapsed() / TICK_COUNT);#ifdef HAL_SLEEP_DEBUG_LEDHAL_TURN_ON_LED3();
#else/* use this to turn LEDs back on after sleep */HalLedExitSleep();
#endif#if ((defined HAL_KEY) && (HAL_KEY == TRUE))/* handle peripherals */(void)HalKeyExitSleep();
#endif/* power on the MAC; blocks until completion */MAC_PwrOnReq();HAL_ENABLE_INTERRUPTS();/* For CC2530, T2 interrupt won抰 be generated when the current count is greater than* the comparator. The interrupt is only generated when the current count is equal to* the comparator. When the CC2530 is waking up from sleep, there is a small window* that the count may be grater than the comparator, therefore, missing the interrupt.* This workaround will call the T2 ISR when the current T2 count is greater than the* comparator. The problem only occurs when POWER_SAVING is turned on, i.e. the 32KHz* drives the chip in sleep and SYNC start is used.*/macMcuTimer2OverflowWorkaround();}else{HAL_ENABLE_INTERRUPTS();}}
}

halSleep(next)的参数next是在osal_pwrmgr_powerconserve()确定,是应用层下一次定时器到的超时时间。

      // Get next time-outnext = osal_next_timeout();

协议栈中有两类定时器,一类是CC2XXX中的定时器由硬件驱动计数;第二类是软件定时器,是由osal_start_timer()、osal_start_reload_timer等定时器设置函数添加到软定时器链表,再由系统时钟进行统一计数,也就是说这些软定时器是通过系统时钟来驱动的。而在OnBoard.h中定义了系统时钟的节拍为1ms,也就是说每过1ms系统时钟就驱动软件时间链表中的定时器减1,当有一个软件定时器计数减到0(也就是说超时了)就删除这个软件定时器并调用osal_set_event()设置相应的事件标志,通知系统需要处理是时候处理这个事件了。

/* OSAL timer defines */#define TICK_TIME   1000   // Timer per tick - in micro-sec

而如前文提到的,有事件要处理时是不能睡眠的,所以进入睡眠之前必须要知道最近的一次定时器超时是长,并在其超时时醒来以及时处理相应的事件。halSleep( )先比较了应用层和MAC层下次超时时间的长短,并取了一个最小的作为睡眠时间,然后调用halSleepSetTimer()来配置睡眠定时器。

      if (timeout != 0){if (timeout > HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME )){timeout -= HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME );halSleepSetTimer(HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME ));}

Zigbee OSAL睡眠管理相关推荐

  1. [ZigBee] 10、ZigBee之睡眠定时器

    0.概述 睡眠定时器用于设置系统进入和退出低功耗睡眠模式之间的周期.睡眠定时器还用于当进入低功耗睡眠模式时,维持定时器2 的定时. 睡眠定时器的主要功能如下: ● 24 位的定时器正计数器,运行在32 ...

  2. Zigbee OSAL NV 区操作

    系统NV区: 初始化nv数据项   osal_nv_item_init() 读取nv数据项      osal_nv_read() 写入nv数据项      osal_nv_write() 在使用os ...

  3. 计算机睡眠管理设置密码,电脑系统windows8系统睡眠唤醒时需要输入密码设置技巧...

    随着越来越多用户安装使用电脑系统windows8,遇到的疑问也就越来越多,因win8在操作上有巨大的改变,所以我们对很多功能设置也会比较生疏.当我们不使用电脑时,会对系统进行设置自动睡眠状态,但为了电 ...

  4. SleeperX macOS睡眠管理软件

    SleeperX 在低电量时自动睡眠.(Hackintosh特性) 在接通电源时,可以自动禁止睡眠. 并且可以随意关闭闲置睡眠或合盖睡眠. 多语言支持 !!! 英文 简体中文 繁体中文 日文(翻译) ...

  5. 实测CC2530 OSAL睡眠唤醒时间、电流、功耗

    使用CC2530间隔10秒钟发送一包数据,所需时间.电流实测如下: 电池电压:2.97V,采样电阻11欧姆. 波形下文图: 参数如下: 1. 完成一次完整的数据交互时间为:30ms 2. 唤醒后系统正 ...

  6. 未火先凉,智能睡眠监测管理平台为何自己先休眠

    图片来源于网络 文 | 魏启扬 来源 | 智能相对论(ID:aixdlun) 凌晨3:23,二胎妈妈肖女士因为身旁的小宝翻了个身被惊醒了.此时,窗外一片寂静,肖女士脑袋无比清醒. 凌晨4:04,在床上 ...

  7. 《ZigBee实战演练》学习笔记

    <ZigBee实战演练>学习笔记 学习者:陈美 版本记录 u 2015/10/17起草 初步了解ZigBee是什么和开发环境的快速建立以及基础实验的第一个实验:点亮第一个LED. u 20 ...

  8. zigbee 休眠与唤醒

    转载自: https://www.cnblogs.com/killer-xc/p/4827754.html 环境:TI CC2530 一.概念 CC2530有五种工作模式.分别为Active mode ...

  9. ZigBee无线传感器的网络协议栈

    小结: Z-Stack协议栈 = OSAL操作系统 + CC2530硬件模块 + AF无线网络应用 协议定义的是一系列的通信标准,通信双方需要共同按照这一标准进行正常的数据收发;协议栈是协议的具体实现 ...

最新文章

  1. iOS开发网络——数据缓存
  2. LeetCode 16 3Sum Closest
  3. html5 绘制图形,HTML5绘制几何图形
  4. CRegKey 注册表操作
  5. python删除重复元素_Python-删除列表中重复元素的方法
  6. ECS 游戏框架背景知识
  7. vue 赋值不改变_【报Bug】超大BUG,Nvue页面引入组件以后,该页面data里的值不能再赋值改变...
  8. 阿里巴巴公布了一份最新的AI成绩单
  9. github打开前端样式丢失_微信小程序入门教程之二:页面样式
  10. swfobject.js
  11. 视频格式mp4转emf
  12. 一维连续傅里叶变换和逆变换公式的一种推导
  13. safari支持java_safari上如何正确启用java插件
  14. 【2】CH347应用--在OpenOCD添加CH347-USB转JTAG接口
  15. HearthBuddy卡牌无法识别
  16. Python图像处理笔记——形态学处理(skimage.morphology)
  17. STM32Cube STM32L053配置GPIO达到最低功耗详解含测量实际电流值
  18. Word控件Spire.Doc 转换教程(十八): 将 RTF 转换为图像并重置图像分辨率
  19. 安装/卸载微软鼠标和键盘中心1603和1612错误
  20. 1T文件夹 - 微云

热门文章

  1. 关于517coding的10月月赛
  2. 2020 CM-BERT: Cross-Modal BERT for Text-Audio Sentiment Analysis
  3. 让System.Drawing.Bitmap可以在linux运行
  4. 滚动距离置零,恢复到初始位置
  5. 漫威所有电影的 按时间线的观影顺序
  6. 盘点业务流程的SAP操作调整
  7. 《AV1 Bitstream Decoding Process Specification》,译名:AV1比特流及解码规范-Chapter 05-语法结构-Section 01~08
  8. mysql数据库全局搜索_数据库全局搜索
  9. python爬虫实战:猫眼电影我不是药神评论
  10. For Your Dream