在学习Zigbee无线传输技术时,为了延长电池的使用寿命,常希望设备在不工作时处于睡眠模式。但是许多时候会遇到比如CC2530在PM2模式下,睡眠定时器唤醒后,可以发送数据,但是无法接受数据,想了很久也不知道问题出在哪里?下面,小编简要的说明一下原因与解决方法。
偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.
全部博文(1760)
分类: Windows平台
2015-02-06 10:21:57
在学习Zigbee无线传输技术时,为了延长电池的使用寿命,常希望设备在不工作时处于睡眠模式。但是许多时候会遇到比如CC2530在PM2模式下,睡眠定时器唤醒后,可以发送数据,但是无法接受数据,想了很久也不知道问题出在哪里?下面,小编简要的说明一下原因与解决方法。
作为示例,小编以简单的cc2530睡眠定时器周期性唤醒CPU为例,讲述如何解决上述问题。首先,需要配置睡眠定时器周期,如下所示通过设置ST0/ST1/ST2寄存器设定周期:
/*
* Sleep timer period set
*/
void wg_setSleepTimerPeriod(float sec)
{
//Note: there is no need to care about overflow of sleep timer
// current value,just about recycle of adder
uint32 sleepTimer = 0;
//once read ST0 value,the current value of 24-bit counter is latched
sleepTimer |= ST0;
sleepTimer |= (uint32)ST1<<8;
sleepTimer |= (uint32)ST2<<16;
sleepTimer += (sec*32768); //low crystal,PM2 mode
ST2 = (uint8)(sleepTimer>>16);
ST1 = (uint8)(sleepTimer>>8);
ST0 = (uint8)sleepTimer; //sleep timer period set
}
在设定睡眠定时器周期之后,需要使能睡眠定时器中断并清除睡眠定时器中断标志,如下所示:
//clear sleep timer flags
STIF = 0; //sleep timer flag
IEN0 |= STIE_BV; //enable sleep timer interrupt
使能睡眠定时器中断标志之后,通过设定SLEEPCMD.MODE就可以使CPU进入特定睡眠模式:
/*
* End device sleep for save power
*/
void wg_analyEdvSavePower(void)
{
/* Prep CC2530 power mode: PM2 */
SLEEPCMD &= ~PMODE; /* clear mode bits */
//Power mode pre-load
SLEEPCMD |= 0x02; /* set mode bits : PM2 */
while (!(STLOAD & LDRDY));
}
根据资料与实验猜想,之所以CPU从PM2模式唤醒之后能发送数据而不能接收数据,是因为当进入睡眠模式后,CPU关闭,16MHz RC与 32MHz 晶振也都关闭,32kHz时钟(RC或者32kHz XOSC)仍然,当CPU唤醒后默认系统主时钟为16MHz的RC时钟,由于32MHz时钟模块并没有开启,所以RF无法接受!当然也就没法接收数据啦,所以正确的解决办法就是:
PCON = PCON_IDLE;
//enter PM2 mode , wake-up and continue run below...
//Wake-up and continue run ...
/* MCU initial:
* system clock set: 32MHz, turn on cache prefetch mode.
*/
clockSetMainSrc(CLOCK_SRC_XOSC);
basicRfReceiveOn(); // turn on rf receiver
wg_waitMs(2); //delay for rf receiver on
HAL_DISABLE_INTERRUPTS();
//re-store IENx(x.0/1/2) SFR
IEN0 = ien0;
IEN1 = ien1;
IEN2 = ien2; //interrupt register
IEN0 &= ~STIE_BV; //disables sleep-timer interrupt
HAL_ENABLE_INTERRUPTS();
如上代码所示,当睡眠唤醒之后,先设置系统主时钟为32MHz外部晶振时钟,并开启RF 接收器,恢复中断控制器IEN0/IEN1/IEN2,并清除睡眠定时中断,开启系统中断!