1.4 深度睡眠模式设置步骤
处理通过调用WFI 指令即可进入睡眠模式,但要进入深度睡眠实现最低的功耗需要正确配置,其步骤如下:
1. 使能ACG 自动时钟门控。这样睡眠模式和深度睡眠模式的外设时钟可以单独控制。
2. 配置寄存器DCGC0、 DCGC1 和DCGC2,设置深度睡眠模式下允许时钟的外设。我们一般只给唤醒CPU 的外设使能时钟,因为允许时钟的外设越少,功耗越低。例如:我们的示例程序在进入深度睡眠模式后是通过PORTB 的外部中断唤醒的,因此在深度睡眠模式下必须允许PORTB 的时钟(置位DCGC2 寄存器的第1 位)。睡眠或深度睡眠模式下,必须设置最少一个唤醒条件,否则无法唤醒。另外值得注意的是,如果程序中设置了定时器中断,并且在睡眠或深度睡眠模式下允许了时钟,则在睡眠或深度睡眠模式下定时器正常工作,当定时器产生中断时,处理器就会被唤醒。
3. 使能深度睡眠位SLEEPDEEP ,使处理器休眠时进入深度睡眠模式。
4. 使能深度睡眠时钟配置寄存器DSLPCLKCFG 的IOSC 位,使处理器在深度睡眠期间将内部振荡器强制为时钟源。
5. 在完成上述配置后,如果想让处理区进入深度睡眠模式,调用WFI 指令即可。睡眠后,发生异常中断即可唤醒处理器。
1.5 示例程序说明
深度睡眠应用示例程序如程序清单 1 所示,在正常运行时时翻转LED 灯,按KEY1 键,进入深度睡眠,按KEY2 键唤醒处理区。程序清单 1(1)定义了深度睡眠需要操作的几个寄存器的地址,2 个按键和一个LED 灯。
程序清单 1(2)定义了函数WFI( ) ,此函数为C 语言内嵌汇编指令的函数。处理器请求休眠是通过汇编指令WFI 来实现的,用户应用程序只需调用函数WFI( ) ,即可请求休眠,关键字__asm 申明该函数内为汇编指令。
程序清单 1(3)定义了配置相关寄存器,使休眠时进入深度休眠,最大程度地实现低功耗的函数DeepSleepConfig( ) 。程序清单 1(4)为中断服务程序,示例程序在此请求休眠挂起。程序清单 1(5)也为中断服务程序,示例程序在此唤醒休眠。
程序清单 1 深度睡眠应用示例程序
#include "hw_memmap.h" #include "hw_types.h" #include "hw_ints.h" #include "sysctl.h" #include "systick.h" #include "gpio.h"#include "interrupt.h"
#define HWREG(x) (*((volatile unsigned long *)(x))) #define SYS_CTL_REG 0xe000ed10 (1)#define SYS_DSLPCLKCFG 0x400FE000 + 0X144 #define SYS_RCC 0x400FE000 + 0X060
#define KEY1 GPIO_PIN_4 // 定义KEY1 #define KEY2 GPIO_PIN_5 // 定义KEY1 #define LED1 GPIO_PIN_1 // 定义LED1
__asm void WFI(void) (2) { WFI }
void DeepSleepConfig() (3) { unsigned long temp;
// ACG 自动时钟门控,睡眠或深度睡眠时使用SCGC 或DCGC 来控制分配给外设的时钟temp = HWREG(SYS_RCC); HWREG(SYS_RCC) = temp|(1<<27);
// 设置深度睡眠下允许时钟外设 SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_GPIOB);
// 设置深度睡眠使能 HWREG(SYS_CTL_REG) = (1<<2);
// 深度睡眠期间将内部振荡器强制为时钟源HWREG(SYS_DSLPCLKCFG) = 1; }
void delay (unsigned int t) { unsigned int i;
do
{
i = 6000;
do{}
while(--i);
}while(--t); }
void InitPB(void)
{ // 使能PB 口 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// 设置连接KEY2 的PB5 为输入GPIODirModeSet(GPIO_PORTB_BASE, KEY2, GPIO_DIR_MODE_IN);
// 设置KEY2 中断的触发方式为低电平触发 GPIOIntTypeSet(GPIO_PORTB_BASE, KEY2, GPIO_LOW_LEVEL);
// 设置PB 的优先级为1 IntPrioritySet(INT_GPIOB, (1<<5));
// 使能KEY2 中断 GPIOPinIntEnable(GPIO_PORTB_BASE, KEY2);
// 使能PB 口中断 IntEnable(INT_GPIOB); }
void InitPD(void)
{ // 使能PD 口 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
// 设置连接KEY1 的PD4 为输入GPIODirModeSet(GPIO_PORTD_BASE, KEY1, GPIO_DIR_MODE_IN);
// 设置连接LED1 的PD7 为输出 GPIODirModeSet(GPIO_PORTD_BASE, LED1, GPIO_DIR_MODE_OUT);
// 设置KEY1 中断的触发方式为低电平触发 GPIOIntTypeSet(GPIO_PORTD_BASE, KEY1, GPIO_LOW_LEVEL);
// 设置PB 的优先级为3 IntPrioritySet(INT_GPIOD, (3<<5));
// 使能KEY1 中断 GPIOPinIntEnable(GPIO_PORTD_BASE, KEY1);
// 使能PD 口中断 IntEnable(INT_GPIOD); }
void GPIO_Port_D_ISR(void) (4)
{ GPIOPinIntClear(GPIO_PORTD_BASE, KEY1); // 清除中断标志 WFI();
}
void GPIO_Port_B_ISR(void) (5) { GPIOPinIntClear(GPIO_PORTB_BASE, KEY2); // 清除中断标志}
int main(void)
{ InitPB (); InitPD (); DeepSleepConfig();
while (1)
{ GPIOPinWrite(GPIO_PORTD_BASE, LED1, ~LED1); // 点亮LED1 delay(100); GPIOPinWrite(GPIO_PORTD_BASE, LED1, LED1); // 熄灭LED1 delay(100);
} }