睡眠及唤醒
- 格式:doc
- 大小:309.00 KB
- 文档页数:14
一、承上启下这一篇,我们来讨论一下CC2430的睡眠功能及唤醒方法。
在实际运用中的CC2430节点一般是靠电池来供电,因此对其功耗的控制显得至关重要。
下面是摘自CC2430中文手册对CC2430的4种功耗模式的介绍:从上表中可看出,CC2430共有4种电源模式:PM0(完全清醒),PM1(有点瞌睡)、PM2(半醒半睡)、PM3(睡的很死)。
越靠后,被关闭的功能越多,功耗也越来越低。
它们之间的转化关系如下:把PM1、PM2唤醒到PM0,有三种方式:复位、外部中断、睡眠定时器中断;但把PM3唤醒到PM0,只有两种方式:复位、外部中断(这是因为在PM3下,所有振荡器均停止工作,睡眠定时器当然也熄火啦~)下面我们通过一个小实验,来介绍如何进入睡眠模式,以及如何唤醒到PM0状态。
二、系统睡眠及中断唤醒实验(1)实验简介系统初始化,处于PM0→进入PM1→1s后被睡眠定时器唤醒为PM0→进入PM2→ 2s后被睡眠定时器唤醒为PM0→进入PM3→等待按键S1按下,触发外部中断,被唤醒为PM0(2)程序流程图(注:上图中的圆角框表示系统的运行状况)(3)实验源码及剖析(下面的框框是可以点的~)头文件及宏定义/*实验说明:中断唤醒睡眠实验,分别介绍三种睡眠模式下的唤醒*/#include <ioCC2430.h>#define LED_ON 0#define LED_OFF 1#define led1 P1_0#define led2 P1_1#define led3 P1_2#define led4 P1_3子函数/*系统时钟初始化-------------------------------------------------------*/ void xtal_init(void){SLEEP &= ~0x04; //都上电while(!(SLEEP & 0x40)); //晶体振荡器开启且稳定CLKCON &= ~0x47; //选择32MHz 晶体振荡器SLEEP |= 0x04;}/*LED初始化-------------------------------------------------------*/ void led_init(void){P1SEL = 0x00; //P1为普通 I/O 口P1DIR |= 0x0F; //P1.0 P1.1 P1.2 P1.3 输出led1 = LED_OFF; //关闭所有LEDled2 = LED_OFF;led3 = LED_OFF;led4 = LED_OFF;}/*外部中断初始化-------------------------------------------------------*/ void io_init(void){P0INP &= ~0X02; //P0.1有上拉、下拉EA = 1; //总中断允许IEN1 |= 0X20; // P0IE = 1,P0中断使能PICTL |= 0X09; //P0.1允许中断,下降沿触发P0IFG &= ~0x02; //P0.1中断标志清0}/*睡眠定时器中断初始化-------------------------------------------------------*/ void sleepTimer_init(void){STIF=0; //睡眠定时器中断标志清0STIE=1; //开睡眠定时器中断EA=1; //开总中断}/*设置睡眠定时器的定时间隔-------------------------------------------------------*/ void setSleepTimer(unsigned int sec){unsigned long sleepTimer = 0;sleepTimer |= ST0; //取得目前的睡眠定时器的计数值sleepTimer |= (unsigned long)ST1 << 8;sleepTimer |= (unsigned long)ST2 << 16;sleepTimer += ((unsigned long)sec * (unsigned long)32768);//加上所需要的定时时长ST2 = (unsigned char)(sleepTimer >> 16); //设置睡眠定时器的比较值ST1 = (unsigned char)(sleepTimer >> 8);ST0 = (unsigned char)sleepTimer;}/*选择电源模式-------------------------------------------------------*/ void PowerMode(unsigned char mode){if(mode<4){SLEEP &= 0xfc; //将SLEEP.MODE清0SLEEP |= mode; //选择电源模式PCON |= 0x01; //启用此电源模式}}/*延时函数-------------------------------------------------------*/void Delay(unsigned int n){unsigned int i,j;for(i=0;i<n;i++)for(j=0;j<1000;j++);}主函数/*主函数-------------------------------------------------------*/ void main(void){xtal_init();led_init();//PM0状态,亮灯并延时led1 = LED_ON; //亮LED1,表示统在PM0模式工作Delay(10);//PM1状态,灭灯setSleepTimer(1); //设置睡眠定时器的定时间隔为1ssleepTimer_init(); //开睡眠定时器中断led1 = LED_OFF;PowerMode(1); //设置电源模式为PM1//1s后,由PM1进入PM0,亮灯并延时led1 = LED_ON;Delay(50);//PM2,灭灯setSleepTimer(2); //设置睡眠定时器的定时间隔为2s led1 = LED_OFF;PowerMode(2); //设置电源模式为PM2//2s后,由PM2进入PM0,亮灯并延时led1=0;Delay(50);//PM3,灭灯io_init(); //初始化外部中断led1 = LED_OFF;PowerMode(3); //设置电源模式为PM3//当外部中断发生时,由PM3进入PM0,亮灯led1 = LED_ON;while(1);}中断服务程序/*外部中断服务程序-------------------------------------------------------*/ #pragma vector = P0INT_VECTOR__interrupt void P0_ISR(void){EA = 0; //关中断Delay(50);if((P0IFG & 0x02 ) >0 ) //按键中断{P0IFG &= ~0x02; //P0.1中断标志清0}P0IF = 0; //P0中断标志清0EA = 1; //开中断}/*睡眠定时器中断服务程序-------------------------------------------------------*/ #pragma vector= ST_VECTOR__interrupt void sleepTimer_IRQ(void){EA=0; //关中断STIF=0; //睡眠定时器中断标志清0EA=1; //开中断}关于如何使用睡眠定时器来唤醒系统,可以总结为如下流程:开睡眠定时器中断→设置睡眠定时器的定时间隔→设置电源模式(注:“设置睡眠定时器的定时间隔”这一步一定要在“设置电源模式”之前,因为进入睡眠后系统就不会继续执行程序了)接下来,我们重点关注一下设置睡眠定时器定时间隔的子函数:setSleepTimer首先对睡眠定时器简单的介绍一下:它是运行于32.768kHz的24位定时器,当系统运行在除了PM3之外的所有的电源模式下,睡眠定时器都会不间断运行。
睡眠定时器使用的寄存器有:ST0,ST1,ST2。
下面是摘自CC2430中文手册对其功能的详细介绍:可以看出,它们的功能包括两方面:读,写。
读:用于读取当前定时器的计数值,读的顺序必须遵循:读ST0 →读ST1 →读ST2写:用于设置定时器的比较值(当定时器的计数值=比较值时,产生中断),写的顺序必须遵循:写ST2 →写ST1 →写ST0OK,接下来我们结合源码来讲解:(1)首先,定义一个unsigned long型变量(32位)sleepTimer,用于接收睡眠定时器的当前计数值:unsigned long sleepTimer = 0;sleepTimer |= ST0; //取得目前的睡眠定时器的计数值sleepTimer |= (unsigned long)ST1 << 8;sleepTimer |= (unsigned long)ST2 << 16;(2)然后加上所需要的定时间隔:sleepTimer += ((unsigned long)sec * (unsigned long)32768);//加上所需要的定时时长此处需要稍微解释一下:为什么1s就代表着32768?因为定时器是工作在32.768kHz之下,所以定时器每加1,需耗时1 /32768 s;加32768,就需要1s;(3)最后将sleepTimer的值作为定时器的比较值:ST2 = (unsigned char)(sleepTimer >> 16); //设置睡眠定时器的比较值ST1 = (unsigned char)(sleepTimer >> 8);ST0 = (unsigned char)sleepTimer;这样,就可成功设置定时器的定时周期啦~(注:至于源码的其他部分,相信结合着详细的注释,大家可以轻松看懂,在此不作赘述)(4)实验结果运行程序,观察LED1,现象为:LED1闪烁(即亮->灭1次),1s后再次闪烁,2s后再次闪烁,然后保持熄灭状态,然后按下S1,LED1亮。
实验现象和预期完全吻合,Over~三、结语吁~ 抽出2天的课余时间,终于搞定了这篇日志。