【WB32库开发】第17章 (二)低功耗电源控制——停止模式

本节使用固件库例程PWR中的PWR_STOP工程,讲解如何配置WB32进入停止模式。

17.3 停止模式实验

本例程演示如何进入低功耗STOP模式和通过外部中断退出低功耗STOP模式;

本例程执行以下操作:

  1. 打开HSE,HSE作为PLL的时钟源,PLL倍频到72MHz,PLL时钟作为主时钟。
  2. 点亮LED1,熄灭LED2。
  3. 等待一段时间后,配置PA0上升沿中断并进入低功耗STOP模式。
  4. 此时处于低功耗STOP模式。按下与PA0连接的按键产生EXTI0中断以唤醒芯片。
  5. 在EXTI0中断中,切换LED2的状态(LED2点亮)。
  6. 由于在进入低功耗STOP模式时关闭了一些时钟配置,所以退出低功耗STOP模式后重新配置相关时钟。
  7. LED1闪烁。

17.3.1 预处理文件、宏定义与函数声明

#include "wb32f10x.h"

EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

void Clock_Config(void);
void EXTI0_Config(void);

void delay(uint32_t n)
{
  while(n--);
}

从实验任务中可以看到,在退出停止模式后需要重新配置时钟,可以看到代码在此处声明了一个时钟配置函数;

17.3.2 main函数

int main(void)
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置系统时钟 */
  Clock_Config();

  /* 配置要使用到的GPIO,PB14为LED1,PB13为LED2 */
  GPIO_Init(GPIOB, GPIO_Pin_13 |GPIO_Pin_14, GPIO_MODE_OUT |GPIO_OTYPE_PP |GPIO_PUPD_NOPULL |GPIO_SPEED_HIGH);
  GPIO_ResetBits(GPIOB, GPIO_Pin_14);   // 打开LED1(PB14设置为低电平)
  GPIO_SetBits(GPIOB, GPIO_Pin_13);     // 关闭LED2(PB13设置为高电平)

  delay(50000000);

  EXTI0_Config();

  /* 进入STOP模式 */
  PWR_EnterSTOPMode(PWR_STOPMode_LP4_S32KOFF, PWR_EntryMode_WFI);

  /* 退出停止模式后, 时钟配置复位, 重新配置时钟 */
  Clock_Config();

  while (1)
  {
    /* LED1闪烁 */
    GPIO_ToggleBits(GPIOB, GPIO_Pin_14);
    delay(8000000);
  }
}

主函数是实现我们想要执行功能的地方,可以对照试验任务简单理解实验过程和每条代码之间的关系;

需要与上一节区分学习的是进入停止模式的函数PWR_EnterSTOPMode(),可以自行对比学习;

另外,熟悉自定义函数的同学可以将GPIO配置部分代码封装,使mian函数更简洁。

17.3.3 时钟配置函数

void Clock_Config(void)
{
  /* 使能APB1CLK. APB1CLK = MAINCLK */
  RCC_APB1CLKConfig(RCC_MAINCLK_Div1, ENABLE);

  /* 使能GPIOD 时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |RCC_APB1Periph_GPIOD, ENABLE);

  /* 配置 PD0 和 PD1为模拟模式 */
  GPIO_Init(GPIOD, GPIO_Pin_0 |GPIO_Pin_1, GPIO_MODE_ANA);

  /* 失能 ANCTL 寄存器 写保护 */
  PWR_UnlockANA();

  /* 使能 HSE */
  ANCTL_HSEConfig(ANCTL_HSE_ON);

  /* 等待HSE直到其启动 */
  if (ANCTL_WaitForHSEStartUp() == ERROR)
  {
    /* 若HSE一直启动失败,则不断等待其启动 */
    while (1);
  }

  /* 配置Flash预载入, 缓存和等待标志位 */
  CACHE->CR = CACHE_CR_CHEEN | CACHE_CR_PREFEN_ON | CACHE_CR_LATENCY_3WS;

  /* 配置AHBCLK1分频, AHBCLK = MAINCLK */
  RCC_AHBCLKConfig(RCC_MAINCLK_Div1);

  /* 使能 APB2CLK. APB2CLK = MAINCLK */
  RCC_APB2CLKConfig(RCC_MAINCLK_Div1, ENABLE);

  /* 锁相环(PLL:Phase Locking Loop)配置: PLLCLK = HSE(12MHz) * 6 = 72MHz */
  RCC_PLLSourceConfig(RCC_PLLSource_HSE_Div2, ENABLE);
  ANCTL_PLLConfig(ANCTL_PLLMul_12);

  /* 使能 PLL */
  ANCTL_PLLCmd(ENABLE);

  /* 等待PLL直到其启动 */
  while(ANCTL_GetFlagStatus(ANCTL_FLAG_PLLRDY) == RESET);

  /* 使能 ANCTL 寄存器写保护 */
  PWR_LockANA();

  /* 选择PLL 作为系统时钟源 */
  RCC_MAINCLKConfig(RCC_MAINCLKSource_PLLCLK);


  /* 使能GPIOA, GPIOB, EXTI和AFIO 时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |RCC_APB1Periph_GPIOA | RCC_APB1Periph_GPIOB | 
                         RCC_APB1Periph_EXTI |RCC_APB1Periph_AFIO, ENABLE);
}

此时钟配置函数不要求全部理解,先跟着代码注释看几遍,能模糊理解其过程就好;

17.3.4 EXTI中断配置函数

void EXTI0_Config(void)
{
  /* 配置 PA0 引脚为下拉输入模式 */
  GPIO_Init(GPIOA, GPIO_Pin_0, GPIO_MODE_IN |GPIO_PUPD_DOWN);

  /* 将PA0映射到EXTI上 */
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

  /* 配置EXTI0*/
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  /* 配置EXTI0的NVIC结构体成员 */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

此处代码也是老面孔了,再提醒一遍:
1)务必注意配置的引脚的模式,这个关乎着配置中断/事件线的检测信号和其他配置;PA0配置为下拉输入模式,则默认PA0的引脚为低电平,若将检测信号配置为下降沿,低电平无法检测到下降沿,则永远无法启动EXTI;

2)配置NVIC结构体成员时,其优先级配置请根据实际工程中所需配置,例程中给出的仅为参考。

17.3.5 EXTI中断服务函数

void EXTI0_IRQHandler(void)
{
  RCC_APB1CLKConfig(RCC_MAINCLK_Div1, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |RCC_APB1Periph_GPIOB |RCC_APB1Periph_EXTI, ENABLE);

  if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  {
    /* 清除EXTI line 0中断标志位 */
    EXTI_ClearITPendingBit(EXTI_Line0);

    /* 翻转LED2状态 */
    GPIO_ToggleBits(GPIOB, GPIO_Pin_13);
  }
}

当检测到中断信号后系统更新对应中断标志位后,进入中断服务函数,执行的主要内容为配置时钟,清除中断标志位和翻转LED2(PB13)的状态;

注意
1)由于系统刚从停止模式唤醒,和睡眠模式相同,唤醒后,若由中断唤醒,先进入中断,退出中断服务程序后,接着执行WFI指令后的程序;若由事件唤醒,直接接着执行WFE后的程序。

2)与睡眠模式不同,当从停止模式唤醒后,WB32会使用HSI作为系统时钟,所以在中断服务函数中,我们使用时钟配置函数将APB1的时钟切换为主时钟(MAINCLK,即由HSE配置的72MHz时钟)。

17.4 实验现象

程序编译后烧录到WB32开发板上,将外部电路连接好,PB14接在示波器通道1上(或LED2的阴极引脚处),PB13接在示波器通道2上(或LED2的阴极引脚处),上电后按下复位可以观察到:
请添加图片描述
CH1(PB14)为低电平,CH2(PB13)为高电平(观察小箭头与通道电平的位置),与main函数起始设置的GPIO状态相同;

接着经过延时,配置了EXTI后,WB32进入stop(停止)模式,不再执行新的代码,等待中断或事件唤醒;

当我们使用杜邦线将PA0与板载3.3V连接在一起后,可以看到:
请添加图片描述
此时由于PA0检测到上升沿,将WB32从停止模式下唤醒,并进入EXTI0中断服务函数,配置好HSE时钟,清除中断标志位后将PB13的电平状态翻转(从高电平翻转为低电平),接着回到主函数里执行循环当中的LED1闪烁的程序;

若想再进入中断,翻转PB13的电平状态,可再将PA0与板载3.3V连接即可:
请添加图片描述
本次实验结果正确,重在理解由用户自定义的系统时钟配置函数部分;

实验结果与睡眠模式相似,停止模式比睡眠模式更省电,主要的原因在于休眠时关闭了所有时钟,所有外设都停止了工作,但其1.8V区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后们还可以从上次停止处继续执行代码。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值