STM32单片机入门学习——第45节: [13-2] 修改频主睡眠模式停止模式待机模式
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!
本文写于:2025.04.22
STM32开发板学习——第45节: [13-2] 修改主频&睡眠模式&停止模式&待机模式
- 前言
- 开发板说明
- 引用
- 解答和科普
- 一、修改主频
- 2、睡眠模式+串口发送+接收
- 3、停止模式+对射式红外传感器计次(D0接在PB14)
- 4、 待机模式+实时时钟(PA0 WKUP引脚上升沿)
- 问题
- 总结
前言
本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!
开发板说明
本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
原理图如下
1、开发板原理图
2、STM32F103C6和51对比
3、STM32F103C6核心板
视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。
下图是实物图
引用
【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)
数据手册
解答和科普
一、修改主频
这两个System文件时配置系统时钟的,配置RCC时钟树,在之前的课程里保持了默认的配置,晶振接的是8M,主频是72M,AHB和APB2是72M, APB1是36M,这些都不是固定可以自己更改。解除只读,找到文件,右键属性,把只读去掉。
修改宏定义如何作用于电路的配置的呢;
这个函数实际上就是一个分配函数,根据你不同的宏定义,选择执行不同的配置函数,
static void SetSysClockTo72(void)
{__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ /* Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;} if (HSEStatus == (uint32_t)0x01){/* Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/* Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |RCC_CFGR_PLLMULL));RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL *//* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; /* Wait till PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}}else{ /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */}
}
#endif
如果你发现你的主频变为8M,那可能是外部晶振有问题了,可以在ELSE加入代码,如果执行到里面,那确实是HSE有问题。
PLL configuration: PLLCLK = HSE * 7 = 56 MHz */ PLL configuration: PLLCLK = HSE * 6 = 48 MHz */
PLL configuration: PLLCLK = (HSE / 2) * 9 = 36 MHz */PLL configuration: = (HSE / 2) * 6 = 24 MHz */Select HSE as system clock source */
首先是SystemInit函数,进来首先启动HSI,之后就是各种缺省配置,最后调用SetSysClock是一个分配函数,根据解除的宏定义,选择执行不同的配置函数,才是真正的配置,比如选择HSE作为锁相环输入,之后锁相环进行9倍频,再选择锁相环输出为主频,这样主频就是72M了。
#include "stm32f10x.h"这个文件已经包含了Systerm文件了,这里不需要包含了。
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"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);}
}
修改主频:
涉及计时计算都要重新匹配一下,或者让这个主频和变量匹配
2、睡眠模式+串口发送+接收
RXD(PA9),对应STM32的Tx引脚;TXD(PA10),对应STM32的Rx引脚
电脑随时都有可能通过串口发送指令,当然也可以不发,为了随时响应指令,STM32就得时刻准备着,所以对于这种靠中断触发,没有中断的时候,就没什么事的代码,我们就可以加入低功耗模式。
SLEEPDEEP和SLEEPONEXIT,需要看内核手册,用操作寄存器的发放进行配置。
//SCB->SCR=0X…
实验中不显示Running了,说明主循环停下来了,CPU正在睡眠,每发送一次Running闪烁一次,这说明,程序在发送一次可以唤醒工作一次,在不影响的情况下,CPU能在空闲时睡眠,节约用电。
唤醒CPU,程序在暂停的地方继续运行,会运行到__WFI之后,但是,唤醒之后,中断也是会立刻申请的,所以在程序调回到while循环开头之前,先进入USART的中断函数,之后回到主循环,回到开头,这时Serial_GetRxFlag()==1,执行数据回传和显示的功能,然后Running闪烁一次,最后程序又来到WFI的位置了。到这里,CPU再次进入睡眠。
3、停止模式+对射式红外传感器计次(D0接在PB14)
OLED_ShowNum(2,7,CounterSensor_Get(),5);
这里一直Get,让没有中断的时候进入低功耗,这个是外部中断,所以可以选择更为省电的停止模式,在停止模式下1.8V时钟关闭,CPU和外设都没有时钟了,但是外部中断的工作是不需要时钟的,可以看到初始化的时候,根本就没有开启EXTI时钟的参数,这也是EXTI能在时钟关闭的情况下工作的原因。
看一看PWR的库函数
void PWR_DeInit(void);
void PWR_BackupAccessCmd(FunctionalState NewState);
void PWR_PVDCmd(FunctionalState NewState);
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel);
void PWR_WakeUpPinCmd(FunctionalState NewState);
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
void PWR_EnterSTANDBYMode(void);
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
void PWR_ClearFlag(uint32_t PWR_FLAG);
这里下载方式不同:按住复位,下载,松手;
停止模式和待机模式,都需要PWR干活,所以都需要开启PWR的时钟,PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI); //进入停止模式
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
{uint32_t tmpreg = 0;/* Check the parameters */assert_param(IS_PWR_REGULATOR(PWR_Regulator));assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));/* Select the regulator state in STOP mode ---------------------------------*/tmpreg = PWR->CR;/* Clear PDDS and LPDS bits */tmpreg &= CR_DS_MASK;/* Set LPDS bit according to PWR_Regulator value */tmpreg |= PWR_Regulator;/* Store the new value */PWR->CR = tmpreg;/* Set SLEEPDEEP bit of Cortex System Control Register */SCB->SCR |= SCB_SCR_SLEEPDEEP;/* Select STOP mode entry --------------------------------------------------*/if(PWR_STOPEntry == PWR_STOPEntry_WFI){ /* Request Wait For Interrupt */__WFI();}else{/* Request Wait For Event */__WFE();}
当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟
这就会导致变慢,最开始的第一次很快,唤醒后变为HIS,因此可以重新启动HSE,配置72Mhz的主频就行了。
4、 待机模式+实时时钟(PA0 WKUP引脚上升沿)
第一,设置RTC闹钟;第二,进入待机模式;第三,使用闹钟信号,唤醒待机模式;
RTC_SetAlarm(RTC_GetCounter()+10);
闹钟寄存器只能写,不能读
PWR_EnterSTANDBYMode();
void PWR_EnterSTANDBYMode(void)
{/* Clear Wake-up flag */PWR->CR |= PWR_CR_CWUF;/* Select STANDBY mode */PWR->CR |= PWR_CR_PDDS;/* Set SLEEPDEEP bit of Cortex System Control Register */SCB->SCR |= SCB_SCR_SLEEPDEEP;
/* This option is used to ensure that store operations are completed */
#if defined ( __CC_ARM )__force_stores();
#endif/* Request Wait For Interrupt */__WFI();
}
待机模式唤醒后,程序从头开始执行,不然闹钟值不会更新,会重新调用System,所以不需要在想停止模式那样,自己调用SystemInit了。PWR_EnterSTANDBYMode();之后的代码,也就执行不到了。同时把外挂模块关闭。
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "MyRTC.h"int main(void)
{OLED_Init();MyRTC_Init();RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);OLED_ShowString(1,1,"CNT :");OLED_ShowString(2,1,"ALR :");OLED_ShowString(3,1,"ALRF :");uint32_t Alarm=RTC_GetCounter()+10;RTC_SetAlarm(Alarm);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,"STANDBY");Delay_ms(1000);OLED_ShowString(4,1," ");Delay_ms(100);OLED_Clear();PWR_EnterSTANDBYMode();}
}
PWR_WakeUpPinCmd(ENABLE);
默认下拉,接上一个高低平,可以唤醒。
问题
总结
本节课主要是了解修改频主&睡眠模式&停止模式&待机模式,对上面的情况进行实验,如何配置完成低功耗模式。