图文概述:



!!!!!!!!注意!!!!!!!!!
每次使用 __WFI()指令或__WFE()指令编程下载后,如需要重新下载其他程序则需要退出睡眠模式,而此时的下载操作为:按住复位键不松手,点击下载程序,然后松手,即可下载新的程序到单片机中.
睡眠模式:
代码:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
/*
在串口通信中,先执行一遍"Running"闪烁后,通过__WFI()指令CPU进入睡眠模式
且等待任一中断唤醒,所以当串口发送数据后会进入USART1通道的中断函数中,
此时唤醒CPU并继续while循环,直到遇见__WFI()指令后继续等待中断唤醒
---睡眠模式可节省耗电---
*/
uint8_t RxData;
int main(void)
{
OLED_Init();
Serial_Init();
OLED_ShowString(1, 1, "RxData:");
while(1)
{
if(Serial_GetRxFlag() == 1)
{
RxData = Serial_GetRxData();
Serial_SendByte(RxData); //将数据传给发送区,让串口助手接收到
OLED_ShowHexNum(1, 8, RxData, 2);
}
OLED_ShowString(2, 1, "Running");
Delay_ms(100);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
__WFI(); //CPU进入睡眠模式并且等待中断唤醒
}
}
关键代码:
__WFI(); //CPU进入睡眠模式并且等待中断唤醒
具体操作对应下图:
停止模式:
代码:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"
/*
本实验的目的---在停止模式下进行对射式红外传感器计次.
通过开启PWR的外设时钟+配置PWR_EnterSTOPMode函数参数,
让PWR进入停止模式,要退出停止模式,则需要等待外部中断唤醒,
所以当每次不计次时(即没有进入外部中断函数),芯片依旧处于停止模式
当对射式红外传感器感应到计数时(此时进入外部中断函数),则唤醒芯片
继续运行之前暂停的程序,以此反复.
*/
int main(void)
{
OLED_Init();
CountSensor_Init();
//开启PWR的外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
OLED_ShowString(1, 1, "CountSensor:");
while(1)
{
OLED_ShowNum(2, 1, CountSensor_Get(), 5);
OLED_ShowString(3, 1, "Running");
Delay_ms(100);
OLED_ShowString(3, 1, " ");
Delay_ms(100);
/*
PWR进入停止模式
---1.指定停止模式下的调节器状态
---2.指定是否使用WFI或WFE指令进入停止模式。
*/
PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
/*
当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟(8MHz),
所以需要重新将RCC时钟配置重置为默认重置状态(即HSE*9 = 72MHz)
*/
SystemInit();
}
}
关键代码:
//开启PWR的外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/*
PWR进入停止模式
---1.指定停止模式下的调节器状态
---2.指定是否使用WFI或WFE指令进入停止模式。
*/
PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
/*
当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟(8MHz),
所以需要重新将RCC时钟配置重置为默认重置状态(即HSE*9 = 72MHz)
*/
SystemInit();
具体操作对应下图:

待机模式:
代码:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"
/*
待机模式(尽量把外部能关的一切耗电电路都关掉,减少耗电)
---程序需要开启PWR的外设时钟以及设置指定的唤醒待机方式
每次运行到PWR_EnterSTANDBYMode函数进入待机模式,
PWR_EnterSTANDBYMode函数以下的代码程序就不会运行
且每次唤醒后,程序会重头开始运行,因此在main程序中可以
去掉while循环
*/
int main(void)
{
OLED_Init();
MyRTC_Init();
//开启PWR的外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
OLED_ShowString(1, 1, "CNT :"); //秒计数器值CNT
OLED_ShowString(2, 1, "ALR :"); //闹钟值Alarm
OLED_ShowString(3, 1, "ALRF:"); //闹钟标志位
/*
1.第一种唤醒方式---WKUP引脚的上升沿(WKUP引脚看芯片引脚图在哪个引脚)
使能芯片的WAKEUP引脚,当WAKEUP引脚上升沿时刻时唤醒待机模式
*/
PWR_WakeUpPinCmd(ENABLE);
/*
2.第二种唤醒方式---RTC闹钟事件的上升沿
设置闹钟为当前时间的10s后(当CNT的值与Alarm的值相同时,会置RTC_FLAG_ALR闹钟标志位为1)
*/
uint32_t Alarm = RTC_GetCounter() + 10;
RTC_SetAlarm(Alarm);
OLED_ShowNum(2, 6, Alarm, 10); //显示Alarm的值
while(1)
{
//获取计数寄存器的值
OLED_ShowNum(1, 6, RTC_GetCounter(), 10);
//获取闹钟标志位
OLED_ShowNum(3, 6, RTC_GetFlagStatus(RTC_FLAG_ALR), 1);
//显示STANDBY,表示处于待机模式中
OLED_ShowString(4, 9, "STANDBY");
Delay_ms(1000);
OLED_ShowString(4, 9, " ");
Delay_ms(100);
OLED_Clear();//清OLED屏(模拟模块断电)
PWR_EnterSTANDBYMode();//进入待机模式
}
}
关键代码:
//开启PWR的外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
/*
1.第一种唤醒方式---WKUP引脚的上升沿(WKUP引脚看芯片引脚图在哪个引脚)
使能芯片的WAKEUP引脚,当WAKEUP引脚上升沿时刻时唤醒待机模式
*/
PWR_WakeUpPinCmd(ENABLE);
/*
2.第二种唤醒方式---RTC闹钟事件的上升沿
设置闹钟为当前时间的10s后(当CNT的值与Alarm的值相同时,会置RTC_FLAG_ALR闹钟标志位为1)
*/
uint32_t Alarm = RTC_GetCounter() + 10;
RTC_SetAlarm(Alarm);
PWR_EnterSTANDBYMode();//进入待机模式
具体操作对应下图:

补充:修改主频
代码:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
/*
修改主频(Delay_ms默认是72MHz)
在默认的主频72MHz下,"Running"字在OLED屏的闪烁周期为1s
通过修改system_stm32f10x.c文件的可写属性,将主频设置为36MHz
此时"Running"字在OLED屏的闪烁周期为2s,即频率延迟了1倍
*/
int main(void)
{
OLED_Init();
OLED_ShowString(1, 1, "SYSCLK:");
OLED_ShowNum(1, 8, SystemCoreClock, 8); //显示系统时钟的主频
while(1)
{
OLED_ShowString(2, 1, "Running");
Delay_ms(500);
OLED_ShowString(2, 1, " ");
Delay_ms(500);
}
}
具体在system_stm32f10x.c文件下的此处修改主频:
