GD32F103VE深度睡眠与唤醒

GD32F103VE深度睡眠与唤醒,执行WFI指令或执行1次WFE指令,命令CPU进入深度睡眠模式。

电源管理单元有3种省电模式:睡眠模式,深度睡眠模式和待机模式;
进入深度睡眠的步骤如下:
1,配置SLEEPDEEP=1
2,配置STBMOD=0
3,执行WFI指令或执行1次WFE指令,命令CPU进入深度睡眠模式。
普通的睡眠模式需要执行两次WFE指令(有点奇怪,实测如此,不清楚原因),命令CPU进入深度睡眠模式。

深度睡眠的结果:
1,关闭Cortex-M3的内核时钟;
2,关闭AHB时钟:SRAM,DMA,FMC,SysTick,SDIO
3,关闭APB时钟:Timer0~Timer13,ADC,APB1外设,APB2外设
4,IRC8M内部RC的8MHz振荡器被关闭;
5,HXTAL外部高速振荡器被关闭;
6,PLL锁相环被关闭;
7,IRC40K内部RC的40KHz振荡器工作,FWDGT独立看门狗定时器启动时会选择IRC40K作为时钟源;
8,LXTAL外部低速振荡器32.768Hz工作,原因是RTC产生报警会让CPU退出待机模式;
9,LDO输出1.2V

EXTI触发源:I/O管脚的16根线和内部模块的4根线(包括LVD、RTC闹钟、USB唤醒、以太网唤醒)。
通过配置GPIO模块的AFIO_EXTISSx寄存器,所有的GPIO管脚都可以被选作EXTI的触发源;
EXTI可以产生中断,也产生事件信号
深度睡眠模式唤醒:
1,采用WFI_CMD进入深度睡眠模式,任何EXTI中断都可以唤醒;
2,采用WFE_CMD进入深度睡眠模式,如果SEVONPEND=0,则任何EXTI事件都可以唤醒;
3,采用WFE_CMD进入深度睡眠模式,如果SEVONPEND=1,则任何中断都可以唤醒;

退出深度睡眠模式后,CPU使用IRC8M内部RC的8MHz振荡器;

#include "DeepSleepMode.h"
#include "delay.h"

/*
电源管理单元有3种省电模式:睡眠模式,深度睡眠模式和待机模式;
进入深度睡眠的步骤如下:
1,配置SLEEPDEEP=1
2,配置STBMOD=0
3,执行WFI指令或执行1次WFE指令,命令CPU进入深度睡眠模式。
而普通的睡眠模式需要执行两次WFE指令(有点奇怪,实测如此,不清楚原因),命令CPU进入深度睡眠模式。

深度睡眠的结果:
1,关闭Cortex-M3的内核时钟;
2,关闭AHB时钟:SRAM,DMA,FMC,SysTick,SDIO
3,关闭APB时钟:Timer0~Timer13,ADC,APB1外设,APB2外设
4,IRC8M内部RC的8MHz振荡器被关闭;
5,HXTAL外部高速振荡器被关闭;
6,PLL锁相环被关闭;
7,IRC40K内部RC的40KHz振荡器工作,FWDGT独立看门狗定时器启动时会选择IRC40K作为时钟源;
8,LXTAL外部低速振荡器32.768Hz工作,原因是RTC产生报警会让CPU退出待机模式;
9,LDO输出1.2V

EXTI触发源:I/O管脚的16根线和内部模块的4根线(包括LVD、RTC闹钟、USB唤醒、以太网唤醒)。
通过配置GPIO模块的AFIO_EXTISSx寄存器,所有的GPIO管脚都可以被选作EXTI的触发源;
EXTI可以产生中断,也产生事件信号
深度睡眠模式唤醒:
1,采用WFI_CMD进入深度睡眠模式,任何EXTI中断都可以唤醒;
2,采用WFE_CMD进入深度睡眠模式,如果SEVONPEND=0,则任何EXTI事件都可以唤醒;
3,采用WFE_CMD进入深度睡眠模式,如果SEVONPEND=1,则任何中断都可以唤醒;

退出深度睡眠模式后,CPU使用IRC8M内部RC的8MHz振荡器;
*/

void Enter_DeepSleepMode0_Use_WFI_CMD(void);
void Enter_DeepSleepMode1_Use_WFE_CMD(void);
void Enter_DeepSleepMode2_Use_WFE_CMD(void);

//函数功能:使用WFI命令使CPU进入深度睡眠模式;任何EXTI中断都可以唤醒;
//唤醒方式: 外部中断;若没有唤醒,再次烧录程序,就会无法烧录;
//测试OK
void Enter_DeepSleepMode0_Use_WFI_CMD(void)
{
	rcu_periph_clock_enable(RCU_PMU);//使能"电源管理单元时钟"外设时钟
	pmu_to_deepsleepmode(PMU_LDO_LOWPOWER,WFI_CMD);
  //PMU_LDO_LOWPOWER命令CPU进入深度睡眠,LDO为低功耗模式	
	//注意:WFI need EXTI interrupt wakeup
}

//函数功能:在SEVONPEND=0时,使用WFE命令使CPU进入深度睡眠模式,任何EXTI事件都可以唤醒;
//测试OK
void Enter_DeepSleepMode1_Use_WFE_CMD(void)
{
	rcu_periph_clock_enable(RCU_PMU);//使能RCU_PMU外设时钟
	system_lowpower_reset(SCB_LPM_WAKE_BY_ALL_INT);//设置SEVONPEND=0
	pmu_to_deepsleepmode(PMU_LDO_NORMAL,WFE_CMD);
	//SLEEPDEEP=1,STBMOD=0,使用WFE命令或执行SEV事件,使CPU进入深度睡眠,但LDO工作
  //唤醒:若通过WFE进入,来自EXTI的任何事件可唤醒,本程序使用外部事件;
}

//函数功能:在SEVONPEND=1时,使用WFE命令使CPU进入深度睡眠模式,任何中断都可以唤醒,如UART,Timer等
//测试OK
void Enter_DeepSleepMode2_Use_WFE_CMD(void)
{
	rcu_periph_clock_enable(RCU_PMU);//使能RCU_PMU外设时钟
	system_lowpower_set(SCB_LPM_WAKE_BY_ALL_INT);//设置SEVONPEND=1
	pmu_to_deepsleepmode(PMU_LDO_NORMAL,WFE_CMD);
	//SLEEPDEEP=1,STBMOD=0,使用WFE命令或执行SEV事件,使CPU进入深度睡眠,但LDO工作
  //唤醒:若通过WFE进入,SEVONPEND=1时,中断可唤醒,本程序使用USART0
}

 

#include "KEY.h"
#include "DeepSleepMode.h"
#include "LED.h"
#include "delay.h"
#include "SYSCLKConfig.h"

/*
GD32F103VE外部中断线线0~15,对应外部IO口的输入中断。
它有7个中断向量,外部中断线0 ~ 4分别对应EXTI0_IRQn ~ EXTI4_IRQn中断向量;
外部中断线 5 ~ 9 共用一个 EXTI9_5_IRQn中断向量;外部中断线10~15 共用一个EXTI15_10_IRQn中断向量。
7个中断向量:EXTI0_IRQn,EXTI1_IRQn,EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn,EXTI9_5_IRQn和EXTI15_10_IRQn。
这7个中断向量对应7个中断服务函数:
EXTI0_IRQHandler();
EXTI1_IRQHandler();
EXTI2_IRQHandler();
EXTI3_IRQHandler();
EXTI4_IRQHandler();
EXTI9_5_IRQHandler();
EXTI15_10_IRQHandler();
*/

void ExternalInterrupt7_Init(void);

//函数功能:初始化ExternalInterrupt7
void ExternalInterrupt7_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOE);//使能GPIOE时钟,enable GPIO clock
	rcu_periph_clock_enable(RCU_AF);//使能复用功能时钟

	gpio_init(GPIOE, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_7);//将GPIOE7设置为浮空输入

	nvic_irq_enable(EXTI5_9_IRQn, 2U, 0U);//设置EXTI5_9_IRQn的中断优先级,抢占优先级为2,子优先级为0
	gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOE, GPIO_PIN_SOURCE_7);
	//设置GE7引脚为外部中断源,select GPIO pin exti sources
  exti_init(EXTI_7, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
	//配置外部中断线使用外部中断7(EXTI_7)
	//中断模式为外部中断(EXTI_INTERRUPT)
	//中断触发方式为下降沿中断(EXTI_TRIG_FALLING)
	exti_interrupt_flag_clear(EXTI_7);//清除外部中断7标志
	exti_interrupt_enable(EXTI_7);//使能外部中断7(EXTI_7)
	exti_event_enable(EXTI_7);//使能外部事件7(EXTI_7)
}

//this function handles external lines 5 to 9 interrupt request
//函数功能:外部中断5~外部中断9的中断服务函数
void EXTI5_9_IRQHandler(void)
{
	FlagStatus ret;

	ret=exti_interrupt_flag_get(EXTI_7);
	//读取外部中断7(EXTI_7)的中断标志
	//get EXTI lines flag when the interrupt flag is set
	if(RESET != ret)
	{
		//退出深度睡眠模式后,CPU使用IRC8M内部RC的8MHz振荡器;
		MySystemClockInit(1,1);//恢复使用外部晶振,带有PLL工作,系统时钟108MHz
	}
	exti_interrupt_flag_clear(EXTI_7);//清除外部中断7标志
}
#include "SYSCLKConfig.h"

void RCU_IRC8M_Clock_Out_Init(void);
void RCU_HXTAL_Clock_Out_Init(void);
void RCU_SYS_Clock_Out_Init(void);
void MySystemClockInit(uint8_t tRCClockSource,uint8_t use_pll);

//函数功能:内部RC8MHz振荡器时钟输出
void RCU_IRC8M_Clock_Out_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOA);//使能GPIOA时钟,enable GPIO clock
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
	//将GPIOA8设置为复用功能IO推挽输出,初始化时钟输出引脚
	//CK_OUT0为时钟输出引脚,映射到PA8引脚
	rcu_ckout0_config(RCU_CKOUT0SRC_IRC8M);
	//设置CK_OUT0引脚(PA8)的输出时钟源为CK_IRC8M(内部RC8MHz)时钟
}

//函数功能:外部8MHz振荡器时钟输出
void RCU_HXTAL_Clock_Out_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOA);//使能GPIOA时钟,enable GPIO clock
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
	//将GPIOA8设置为复用功能IO推挽输出,初始化时钟输出引脚
	//CK_OUT0为时钟输出引脚,映射到PA8引脚
	rcu_ckout0_config(RCU_CKOUT0SRC_HXTAL);
	//设置CK_OUT0引脚(PA8)的输出时钟源为CK_HXTAL(外部8MHz)时钟
}

//函数功能:将CK_OUT0映射到PA8引脚,输出系统时钟;
void RCU_SYS_Clock_Out_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOA);//使能GPIOA时钟,enable GPIO clock
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
	//将GPIOA8设置为复用功能IO推挽输出,初始化时钟输出引脚
	//CK_OUT0为时钟输出引脚,映射到PA8引脚
	rcu_ckout0_config(RCU_CKOUT0SRC_HXTAL);
	//设置CK_OUT0引脚(PA8)的输出时钟源为CK_HXTAL(外部8MHz)时钟
}

//MySystemClockInit(0,1);//使用内部RC振荡器,带有PLL工作,系统时钟108MHz
//MySystemClockInit(1,1);//使用外部晶振,带有PLL工作,系统时钟108MHz
//MySystemClockInit(0,0);//直接使用内部RC振荡器,不带PLL工作,系统时钟8MHz
//MySystemClockInit(1,0);//直接使用外部晶振,不带PLL工作,系统时钟8MHz
//函数功能:系统时钟初始化
void MySystemClockInit(uint8_t tRCClockSource,uint8_t use_pll)
{
///选择"振荡源"开始//
	if(tRCClockSource==0)//内部RC时钟
	{
	  rcu_osci_on(RCU_IRC8M);//启用"内部RC8MHz振荡器"
	  rcu_osci_stab_wait(RCU_IRC8M);//等待内部RC8MHz振荡器稳定
	}
	else//内部高速晶振时钟
	{
	  rcu_osci_on(RCU_HXTAL);//启用"外部8MHz晶振"
	  rcu_osci_stab_wait(RCU_HXTAL);//等待外部8MHz晶振振荡器稳定
	}
///选择"振荡源"结束//

///选择"PLL时钟源"开始//
	if(use_pll)//使用PLL
	{
		if(tRCClockSource==0)//内部RC时钟
	  {
	    rcu_pll_config(RCU_PLLSRC_IRC8M_DIV2,RCU_PLL_MUL27);
	    //设置内部RC8MHz输出的时钟再2分频后作为PLL输入时钟源,并设置倍频因子为27
		  rcu_osci_on(RCU_PLL_CK);//使能"PLL时钟"
		  rcu_osci_stab_wait(RCU_PLL_CK);//等待"PLL时钟"稳定
	  }
	  else
	  {
	    rcu_predv0_config(RCU_PREDV0_DIV2);//设置外部晶振输出后再进行2分频得到的时钟
	    rcu_pll_config(RCU_PLLSRC_HXTAL,RCU_PLL_MUL27);
	    //设置外部晶振8MHz输出的时钟再2分频后作为PLL输入时钟源,并设置倍频因子为27

	    rcu_osci_on(RCU_PLL_CK);//使能"PLL时钟"
	    rcu_osci_stab_wait(RCU_PLL_CK);//等待"PLL时钟"稳定
	  }
  }
///选择"PLL时钟源"结束//

///选择"系统时钟源"开始//
	if(use_pll)//使用PLL
	{
	  rcu_system_clock_source_config(RCU_CKSYSSRC_PLL);
	  //选择选择CK_PLL时钟作为系统时钟CK_SYS
  }
	else
	{
	  if(tRCClockSource==0)//内部RC时钟
	  {
	    rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
	    //直接选择内部RC8MHz输出的时钟CK_IRC8M作为系统时钟CK_SYS
		}
		else
		{
	    rcu_system_clock_source_config(RCU_CKSYSSRC_HXTAL);
	    //直接选择外部晶振时钟输出的CK_HXTAL时钟作为系统时钟CK_SYS
	  }
  }
///选择"系统时钟源"结束//
}
#include "LED.h"

void LED_Init(void);

//函数功能:初始化MCU_Led
void LED_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOD);//使能GPIOD时钟,enable GPIO clock

	gpio_init(GPIOD, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
	//将GPIOD15设置为输出上拉

	MCU_Led_Off();
//	GPIO_BC(GPIOD) = GPIO_PIN_15;//清除GPIOD15输出,GPIO bit clear register
}
#ifndef __LED_H
#define __LED_H

#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t

#define MCU_Led_Off()  GPIO_BOP(GPIOD)=GPIO_PIN_15  //GD15输出高电平
#define MCU_Led_On() GPIO_BC(GPIOD)=GPIO_PIN_15   //GD15输出低电平
#define MCU_Led_Toggle() gpio_bit_write( GPIOD,GPIO_PIN_15,(bit_status)((1-gpio_input_bit_get(GPIOD,GPIO_PIN_15))) )
//GD15取反输出电平

extern void LED_Init(void);

#endif

main.c如下:

#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#include "delay.h"

#include "LED.h"
#include "KEY.h"
#include "DeepSleepMode.h"
#include "SYSCLKConfig.h"

//PC13仅可以作为RTC功能引脚
//PC14和PC15可以作为通用I/O口或外部32.768KHz低速晶振引脚
int main(void)
{
	//MySystemClockInit(1,1);

	//NVIC_PRIGROUP_PRE4_SUB0:抢占优先级为4bit(取值为0~15),子优先级为0bit(没有响应优先级)
	//NVIC_PRIGROUP_PRE3_SUB1:抢占优先级为3bit(取值为0~7),子优先级为1bit(取值为0~1)
	//NVIC_PRIGROUP_PRE2_SUB2:抢占优先级为2bit(取值为0~3),子优先级为2bit(取值为0~3)
	//NVIC_PRIGROUP_PRE1_SUB3:抢占优先级为1bit(取值为0~1),子优先级为3bit(取值为0~7)
	//NVIC_PRIGROUP_PRE0_SUB4:抢占优先级为0bit(没有抢占优先级),子优先级为3bit(取值为0~15)
	nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);//设置系统中断优先级"抢占优先级为4bit,子优先级为0bit"

  INTX_ENABLE();//开启所有中断

	LED_Init();//初始化MCU_Led

	delay_init();//系统时钟配置

	ExternalInterrupt7_Init();//初始化ExternalInterrupt7


//	Enter_DeepSleepMode0_Use_WFI_CMD();//使用WFI命令使CPU进入深度睡眠模式;任何EXTI中断都可以唤醒;
//  Enter_DeepSleepMode1_Use_WFE_CMD();//在SEVONPEND=0时,使用WFE命令使CPU进入深度睡眠模式,任何EXTI事件都可以唤醒;
  Enter_DeepSleepMode2_Use_WFE_CMD();//在SEVONPEND=1时,使用WFE命令使CPU进入深度睡眠模式,任何中断都可以唤醒,如UART,Timer等

//PE7中断唤醒后,执行下面的代码//
	while(1)//唤醒后,则灯闪烁
	{
		delay_ms(500);
		MCU_Led_Toggle();
	}
}

GD32F103VE深度睡眠与唤醒_第1张图片

 

你可能感兴趣的:(产品研发,单片机,嵌入式硬件,GD32)