天天看点

CC2530从睡眠到主动模式

  从

PM1

PM2

到切换到

PM0

,可以使用睡眠定时器,因为睡眠定时器计时时间到后,

MCU

会产生睡眠定时器中断,电源模式会自动从

PM1/PM2

切换到

PM0

。在

PM3

下,睡眠定时器不起作用,因为

32K

的晶振都关闭了,故从

PM3

切换到

PM0

用的是外部

IO

中断。

  

设置睡眠定时器的定时间隔

这一步一定要在

设置电源模式

之前,因为进入睡眠后系统就不会继续执行程序了。读取睡眠定时器的当前计数值,顺序必须遵循

读ST0 -> 读ST1 -> 读ST2

的顺序;写入睡眠定时器的比较值,顺序必须遵循

写ST2 -> 写ST1 -> 写ST0

的顺序。

ST

的计数时钟是

32.768K

,向上计数,当定时器的计数值等于比较值时,产生中断。

#include <iocc2530.h>

#define uint unsigned int
#define uchar unsigned char
#define uint8 unsigned char
#define uint32 unsigned long

#define LED_ON  0
#define LED_OFF 1

#define gled    P1_0
#define rled    P1_1
#define crystal 0 /* 石英晶振 */
#define rc      1 /* RC晶振 */
#define s1      P0_1

void delay ( uint n ) {
    uint i, j;

    for ( i = 0; i < 50; i++ )
        for ( j = 0; j < n; j++ );
}

void initKey ( void ) {
    P0SEL &= ~0X02;
    P0DIR &= ~0X02;
    P0IEN |= 0X02;
    IEN1 |= 0X20;
    EA = 1;
}

void initled ( void ) {
    P1SEL &= ~0X03;
    P1DIR |= 0X03;
    rled = 1;
    gled = 1;
}

void set_main_clock ( int source ) {
    if ( source ) {
        CLKCONCMD |= 0X40; /* 选择16MHz的RCOSC为系统时钟源 */
        while ( ! ( CLKCONSTA & 0X40 ) ); /* 等待时钟稳定 */
    } else {
        CLKCONCMD &= ~0X40; /* 选择32MHz的XOSC为系统时钟源 */
        while ( CLKCONSTA & 0X40 ); /* 等待时钟稳定 */
    }
}

void set_low_clock ( int source ) {
    if ( source ) {
        CLKCONCMD |= 0X80; /* 选择32KHz的RCOSC为低速时钟源 */
    } else {
        CLKCONCMD &= ~0X80; /* 选择32KHz的XOSC为低速时钟源 */
    }
}

void init_sleep_timer ( void ) {
    ST2 = 0X00;
    ST1 = 0X00;
    ST0 = 0X00;
    EA = 1;
    STIE = 1; /* 使能睡眠定时器中断 */
    STIF = 0; /* 清除睡眠定时器中断标志 */
}

void blink_led ( void ) {
    gled = 1;
    uchar jj = 10;

    while ( jj-- ) {
        rled = !rled;
        delay ( 10000 );
    }

    rled = 1;
    gled = 0;
}

void set_st_period ( uint sec ) { /* 设置睡眠时间 */
    uint32 sleeptimer = 0;
    /* 把ST2:ST1:ST0赋值给sleeptimer */
    sleeptimer |= ( uint32 ) ST0;
    sleeptimer |= ( ( uint32 ) ST1 << 8 );
    sleeptimer |= ( ( uint32 ) ST2 << 16 );
    /* 低速频率为32.768KHz,故每秒定时器计数32768次 */
    sleeptimer += ( ( uint32 ) sec * ( uint32 ) 32768 );
    /* 把加上N秒后的的计数值赋给ST2:ST1:ST0 */
    ST2 = ( uint8 ) ( sleeptimer >> 16 );
    ST1 = ( uint8 ) ( sleeptimer >> 8 );
    ST0 = ( uint8 ) sleeptimer;
}

void set_powermode ( uchar mode ) {
    uchar i;

    if ( mode < 4 ) {
        SLEEPCMD &= ~0X03;
        SLEEPCMD |= mode;

        for ( i = 0; i < 4; i++ );

        PCON = 1;
    } else {
        PCON = 0;
    }
}

void main ( void ) {
    set_main_clock ( crystal );
    set_low_clock ( crystal );
    initled();
    init_sleep_timer();
    gled = LED_ON;
    delay ( 50000 );
    /* 进入PM1模式 */
    gled = LED_OFF;
    set_st_period ( 5 );
    set_powermode ( 1 );
    rled = LED_ON;
    delay ( 50000 );
    /* 进入PM2模式 */
    rled = LED_OFF;
    set_st_period ( 5 );
    set_powermode ( 2 );
    gled = LED_ON;
    delay ( 50000 );
    gled = LED_OFF;
    initKey(); /* 初始化按键 */
    set_powermode ( 3 );
    rled = LED_ON;

    while ( 1 );
}

/* 睡眠定时器中断函数 */
#pragma vector = ST_VECTOR
__interrupt void ST_ISR ( void ) {
    EA = 0;
    STIF = 0; /* 标志清除 */
    EA = 1;
}

#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR ( void ) { /* P0中断函数 */
    EA = 0;
    P0IF = 0;
    P0IFG &= ~0X02;
    /* 只要响应了IO中断,就会从PM1/PM2/PM3恢复到PM0,故本句也可以取消 */
    set_powermode ( 4 );
    EA = 1;
}
           

继续阅读