大家都知道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 );
我們可以按照上面的方法寫一個自己需要的任務來完成某種功能,比如說隔一段時間采集溫度,然后把數據發送出來。
|