×

STM32F103C8T6------待机唤醒(外部中断)

zxjy辉 zxjy辉 发表于2022-11-03 15:56:05 浏览328 评论0

抢沙发发表评论

高清自然山水风景.jpeg

  1. 实现过程

    1. 需要用到的资源包括PWR和EXTI这两个

    2. 首先就是开启对应的PWR时钟 EXTI时钟,引脚的外设时钟,中断向量控制表

  2. 实现代码

    1. 进入待机的方法一共有3中的休眠方式:睡眠模式、停机模式、待机模式;节能的效果是待机模式最好,其次是停机模式,最次是睡眠模式

      图片.png

    2. 本次采用的休眠方式,就是停机模式,然后采用外部中断进行唤醒

    3. 进入休眠的代码:

    4.       RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR, ENABLE );        //要开启对应的电源控制时钟 
      //     PWR_WakeUpPinCmd( ENABLE );                      //这个是使用wakeUP引脚的时候需要使用的 
      //     PWR_EnterSTANDBYMode();                         //进入待机模式
      //     __WFE;                                 //调用ARM内核指令,进入睡眠模式,并且以事件唤醒
            PWR_EnterSTOPMode( PWR_Regulator_LowPower, PWR_STOPEntry_WFI );   //进入停机模式
    5. ///设置一个外部中断,对应的引脚是 PA11
      void PA11_EXTI_Config(){
        GPIO_InitTypeDef GPIO_InitStructure;
          EXTI_InitTypeDef EXTI_InitStructure;
          NVIC_InitTypeDef NVIC_InitSrurcture;
          
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_Init( GPIOA, &GPIO_InitStructure);
          
          GPIO_EXTILineConfig( GPIO_PortSourceGPIOA, GPIO_PinSource11 );          //这个连接不要忘记了,选择那个引脚作为外部中断线
          EXTI_InitStructure.EXTI_Line = EXTI_Line11;
          EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
          EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
          EXTI_InitStructure.EXTI_LineCmd = ENABLE;
          EXTI_Init( &EXTI_InitStructure );
          
          NVIC_InitSrurcture.NVIC_IRQChannel = EXTI15_10_IRQn;
          NVIC_InitSrurcture.NVIC_IRQChannelPreemptionPriority =0;
          NVIC_InitSrurcture.NVIC_IRQChannelSubPriority = 1;
          NVIC_InitSrurcture.NVIC_IRQChannelCmd = ENABLE;
          NVIC_Init( &NVIC_InitSrurcture );
          
      }


    6. ///RTC相关初始化:利用这个是的在定时器时间到来的时候,进入休眠
      void Wake_Up_RTC_Config(){
          RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE );     //使能PWR时钟
          PWR_BackupAccessCmd( ENABLE );
          BKP_DeInit();
          RCC_LSICmd( ENABLE );                                 //使能内部时钟
          while( RCC_GetFlagStatus( RCC_FLAG_LSIRDY ) != SET ){               //判断时候开启了内部时钟
          }
          printf("内部低速时钟开启成功\r\n");
            RCC_RTCCLKConfig( RCC_RTCCLKSource_LSI );                     //使用内部低速时钟
          RCC_RTCCLKCmd( ENABLE );                                //使能RTC时钟
          
          RTC_WaitForLastTask();                                  //等待上一次的寄存器操作
          RTC_WaitForSynchro();                                  //等待寄存器同步
          RTC_ITConfig( RTC_IT_SEC | RTC_IT_ALR, ENABLE );                  //使能秒中断 和警报中断
            RTC_WaitForLastTask();
            RTC_EnterConfigMode();    
          RTC_SetPrescaler(40000);                                 //设置分频数
          RTC_WaitForLastTask();
          RTC_SetCounter(1);                                    //设置起始数值为0
          RTC_WaitForLastTask();
          RTC_SetAlarm(10);                                    //设置闹钟时间为10s
          RTC_WaitForLastTask();
          RTC_ExitConfigMode();
       
          
          Wake_Up_RTC_NVIC_Config();
      }
      void Wake_Up_RTC_NVIC_Config(){
        NVIC_InitTypeDef RTC_InitStructure;
          
          RTC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
          RTC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
          RTC_InitStructure.NVIC_IRQChannelSubPriority = 2;
      
          NVIC_Init( &RTC_InitStructure );
          
      
      }


    7. ///使用RTC时钟进行进入停机模式,也就是在RTC中断中实现的
      void RTC_IRQHandler(){
       if( RTC_GetITStatus( RTC_IT_ALR ) == SET ){            //如果RTC闹钟被置位了
           wake_flag = 1;                         //在函数中判断,如果为1 就在主函数中调用 进入休眠的代码
           RTC_ClearITPendingBit( RTC_IT_ALR );              //清除标志位
       }
       if( RTC_GetITStatus( RTC_IT_SEC ) == SET ){            //如果秒中断被置位了
           printf("当前时间:%d s\r\n", RTC_GetCounter());            //打印出当前的秒数
           RTC_ClearITPendingBit( RTC_IT_SEC );              //清除标志位
       }
         RTC_WaitForLastTask();
      }
    8. //由于,在停机模式下,只要是受到外部中断,就会退出停机状态
      void EXTI15_10_IRQHandler(){
       if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_11) == 0 ){
        GPIO_SetBits(GPIOB,GPIO_Pin_0); 
          GPIO_ResetBits(GPIOB,GPIO_Pin_1); 
           printf("按下K1\r\n");
         
       }
       //清除标志位
       EXTI_ClearITPendingBit(EXTI_Line11|EXTI_Line12);
      }
    9. //在主函数的死循环中,添加这个
      if( wake_flag == 1 ){
                  PWR_Enter_STANDBYMode();
                      wake_flag = 0;
                      SystemInit();         //系统时间需要重新进行初始化
                      SysTick_init();         //这个滴答定时器,也是要重新初始化
                      usart1_config(9600,1);//串口1波特率9600接收中断,这个串口在这里要重新配置的
                  }
  3. 注意事项

    1. 唤醒的中断(外部中断)的优先级,最好是要高于进入休眠的的中断,而且最好不要在中断中进入休眠,可以用一个标志位进行判断,在中断中进入容易卡住

    2. STM32的工作电压(VDD)为2.0~3.6V。通过内置的电压调节器提供所需的1.8V电源。当主电源VDD掉电后,通过VBAT脚为实时时钟(RTC)和备份寄存器提供电源。

      图片.png

    3. 可以看出VDD为STM32提供供电,通过内置的电压调节器提供所需的1.8V电源,1.8V供电区域为CPU核心存储器和内置数字外设。

    4. VBAT是后备供电也就是通过后备电池来供电的。其供电区域为LSE 32K晶体振荡器、后备寄存器RCC BDCR和寄存器RTC。也就是说内部的晶振是停止掉了

    5. 最重要的一点就是,在唤醒之后,(休眠的时候,会保护现场?)一定要记得重新对系统时钟进行初始化:SystemInit();     //系统时间需要重新进行初始化,官方库函数

    6. 重复进入休眠状态,会取反。也就是当下是休眠的,再进入一次休眠程序,就会退出休眠状态


#好好学习!

群贤毕至

访客