0%

13-2修改主频&睡眠模式&停止模式&待机模式

修改主频

system_stm32f10x.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1.  This file provides two functions and one global variable to be called from 
* user application:
* - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
* factors, AHB/APBx prescalers and Flash settings).
* This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32f10x_xx.s" file.
*
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
* 2. After each device reset the HSI (8 MHz) is used as system clock source.
* Then SystemInit() function is called, in "startup_stm32f10x_xx.s" file, to
* configure the system clock before to branch to main program.
*
* 3. If the system clock source selected by user fails to startup, the SystemInit()
* function will do nothing and HSI still used as system clock source. User can
* add some code to deal with this issue inside the SetSysClock() function.
*
* 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depedning on
* the product used), refer to "HSE_VALUE" define in "stm32f10x.h" file.
* When HSE is used as system clock source, directly or through PLL, and you
* are using different crystal you have to adapt the HSE value to your own
* configuration.

SystemInit()这个函数用来配置时钟树,在main函数之前自动调用

SystemCoreClock表示主频频率的值,显示此变量,可以知道目前主频的值。

SystemCoreClockUpdate()更新SystemCoreClock,因为这个变量只要最开始的一次赋值,改变主频频率,该值不会跟着改变。

1
2
3
4
5
6
7
8
9
10
11
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
#define SYSCLK_FREQ_24MHz 24000000
#else
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000
#endif

想要修改主频值,解除注释。默认的主频是72000000(72M)

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

int main(void)
{
OLED_Init();
OLED_ShowString(1,1,"SYSCLK:");
OLED_ShowNum(1,8,SystemCoreClock,8);//显示当前的主频值,可以在system_stm32f10x.c中修改

while(1)
{
//在默认的72M主频下,Running每500ms显示一次,修改主频,显示时间会变化,因为主频改变了。比如主频改成36M,Runing每1S显示一次。如果想要修改主频之后,Running仍500ms显示一次,需要修改Delay函数。可见不能随意修改主频。
OLED_ShowString(2,1,"Running");
Delay_ms(500);
OLED_ShowString(2,1," ");
Delay_ms(500);
}
}

睡眠模式+串口发送+接收

因为主循环一直在运行,空闲时运行没有意义,还费电。
因此靠中断触发,没有中断就没作用的程序,可以加入低功耗模式。

由于程序需要使用串口USART硬件电路接收数据,只能使用睡眠模式,不能使用停止模式或待机模式,因为停止模式和待机模式下CPU和外设都不能运行,无法正常接收串口数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
uint8_t RxData;
int main(void)
{
//初始化,配置串口
OLED_Init();
OLED_ShowString(1,1,"RxData:");
Serial_Init();
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();//中断唤醒

//__WFE();//事件唤醒
}
}

通过串口给单片机发送数据,每发送一次数据,进入中断,单片机会被唤醒,Running闪烁一次。

停止模式+对射式红外传感器计次

对射式红外传感器计次使用外部中断触发唤醒,可以进入更省电的停止模式。
在停止模式下,1.8V区域时钟关闭,CPU和外设都没有时钟,但是外部中断的工作不需要时钟。

常用函数

1
void PWR_DeInit(void);

恢复PWR缺省配置

1
void PWR_BackupAccessCmd(FunctionalState NewState);

使能后备区域访问

1
void PWR_PVDCmd(FunctionalState NewState);

使能PVD功能

1
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel);

配置PVD的阈值电压

1
void PWR_WakeUpPinCmd(FunctionalState NewState);

使能位于PA0位置的WKUP引脚,配合待机模式使用

1
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);

进入停止模式

1
void PWR_EnterSTANDBYMode(void);

进入待机模式

1
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);

获取标志位

1
void PWR_ClearFlag(uint32_t PWR_FLAG);

清除标志位

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"


int main(void)
{
OLED_Init();
CountSensor_Init();

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR外设的时钟

OLED_ShowString(1,1,"Count:");

while(1)
{
OLED_ShowNum(1,7,CountSensor_Get(),5);

OLED_ShowString(2,1,"Running");
Delay_ms(100);
OLED_ShowString(2,1," ");
Delay_ms(100);

PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);//进入停止模式
SystemInit();//配置时钟
}
}

待机模式 + 实时时钟

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
OLED_Init();
MyRTC_Init();

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//开启PWR时钟


OLED_ShowString(1,1,"CNT:");
OLED_ShowString(2,1,"ALR:");
OLED_ShowString(3,1,"ALRF:");

PWR_WakeUpPinCmd(ENABLE);//WKUP引脚唤醒

uint32_t Alarm = RTC_GetCounter() + 10;
RTC_SetAlarm(RTC_GetCounter() + 10);
OLED_ShowNum(2,6,Alarm,10);

while(1)
{
OLED_ShowNum(1,6,RTC_GetCounter(),10);
OLED_ShowNum(3,6,RTC_GetFlagStatus(RTC_FLAG_ALR),1);

OLED_ShowString(4,1,"Running");
Delay_ms(100);
OLED_ShowString(4,1," ");
Delay_ms(100);

PWR_EnterSTANDBYMode();//进入待机模式
}

}

进入待机模式后,闹钟触发一次,程序从头开始执行。