从
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;
}