找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4234|回复: 0
打印 上一主题 下一主题
收起左侧

zigbee休眠机制

[复制链接]
跳转到指定楼层
楼主
ID:76127 发表于 2015-4-18 00:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  大家都知道2430有3种睡眠模式,pm2模式比较省功耗而且可以被定时唤醒;pm3模式最省电但是只能被外部中断唤醒。开启睡眠功能很简单:
首先确认\Texas Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Tools\CC2430DB目录下的f8wConfig.cfg文件中DRFD_RCVC_ALWAYS_ON定义为FALSE;
然后在IAR的Options->C/C++Compiler->Defined symbols中添加“POWER_SAVING”;
最后在Options->Linker->Linker command line里面把f8w2430.xcl改为f8w2430pm.xcl。
在定义“POWER_SAVING”宏以后OSAL.c中的osal_start_system()函数里面就会调用 osal_pwrmgr_powerconserve()函数。osal_pwrmgr_powerconserve()函数把获取os层timer的下一次的到时时间作为参数,调用hal_sleep()进入pm2睡眠模式,如果当前没有任务那么将进入pm3。所以说一旦启用省电模式,系统将根据当前的任务自动进入睡眠,睡眠前设置sleeptimer,醒来的时间刚好等于下次任务到来的时间,当完成任务后再次进入睡眠。
ZStack中的hal_sleep()函数功能比较多,看着比较头晕,所以我写了一个简化版本供大家来讨论:

01 void halSleep ( uint16 osal_timeout )
02 {
03     uint32         timeout = 0 ;
04     halIntState_t intState , ien0 , ien1 , ien2 ;
05
06     /* 把osal_timeout 转换为320微秒为单位 */
07     timeout = HAL_SLEEP_MS_TO_320US (osal_timeout );
08   
09     /*如果osal_timeout 小于最小安全睡眠时间*/
10     if (timeout < HAL_SLEEP_MS_TO_320US (PM_MIN_SLEEP_TIME ))
11     {
12       return ;
13     }
14     /*如果osal_timeout 大于sleeptimer最大范围*/
15     else if (timeout > HAL_SLEEP_MS_TO_320US ( MAX_SLEEP_TIME ))
16     {
17       timeout = HAL_SLEEP_MS_TO_320US ( MAX_SLEEP_TIME );
18     }
19
20
21     HAL_ENTER_CRITICAL_SECTION (intState );
22     if (MAC_PwrOffReq (MAC_PWR_SLEEP_DEEP ) == MAC_SUCCESS )/* 关闭RF*/
23     {
24      /* 切换外部时钟*/
25      HAL_SLEEP_SET_MAIN_CLOCK_RC ();
26
27     /* 设置sleeptimer到时时间 */
28     halSleepSetTimer (timeout );
29        /* 设置sleeptimer中断 */
30     HAL_SLEEP_TIMER_CLEAR_INT ();
31     HAL_SLEEP_TIMER_ENABLE_INT ();
32
33     /* 保存其他所有中断,并屏蔽 */
34        HAL_SLEEP_IE_BACKUP_AND_DISABLE (ien0 , ien1 , ien2 );
35      
36        /* This is to check if the stack is exceeding the disappearing
37          * RAM boundary of 0xF000. If the stack does exceed the boundary
38          * (unlikely), do not enter sleep until the stack is back to normal.
39          *保证栈在异常边界不进入睡眠模式,具体原因不是很清楚,为了安全还是加上
40          */
41        if ( ((uint16 )(* ( __idata uint16 * )(CSTK_PTR )) >= 0xF000 ) )
42        {
43           HAL_EXIT_CRITICAL_SECTION (intState );
44
45           /* 此处直接进入pm2,程序运行在此处停止,直到sleeptimer到时,再接着向下运行 */
46           HAL_SLEEP_SET_POWER_MODE (CC2430_PM2 );
47
48           HAL_ENTER_CRITICAL_SECTION (intState );
49        }
50
51     /* 恢复中断 */
52        HAL_SLEEP_IE_RESTORE (ien0 , ien1 , ien2 );
53
54     /* 关掉sleeptimer中断 */
55        HAL_SLEEP_TIMER_DISABLE_INT ();
56
57     /* 设置晶振*/
58     HAL_SLEEP_SET_MAIN_CLOCK_CRYSTAL ();
59
60     /* 打开RF*/
61     MAC_PwrOnReq ();
62
63     /*调整回系统时间*/
64     osal_adjust_timers (osal_timeout );
65
66      }
67   
68     HAL_EXIT_CRITICAL_SECTION (intState );
69 }

在应用方面,以Samples中的GenericApp为例。在GenericApp.c中,GenericApp_ProcessEvent里面有一个 GENERICAPP_SEND_MSG_EVT消息,该消息会用GenericApp_SendTheMessage()给coordinater发送一个“Hello World”字符串。发送后设置Timer来再次触发此消息,时间间隔为5秒钟。我们可以把下面这句添加进 GenericApp_Init()函数里,这样的话系统上电后就启动此任务,5秒发送一次“Hello World”:
osal_start_timerEx( GenericApp_TaskID,GENERICAPP_SEND_MSG_EVT,GENERICAPP_SEND_MSG_TIMEOUT );

我们可以按照上面的方法写一个自己需要的任务来完成某种功能,比如说隔一段时间采集温度,然后把数据发送出来。


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表