当前位置: 首页 > news >正文

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);
在这里插入图片描述
默认下拉,接上一个高低平,可以唤醒。

问题

总结

本节课主要是了解修改频主&睡眠模式&停止模式&待机模式,对上面的情况进行实验,如何配置完成低功耗模式。

相关文章:

  • 详解Node.js中的setImmediate()函数
  • Android自动化功能-使用Appium获取android页面节点元素信息
  • IDEA中如何统一项目名称/复制的项目如何修改根目录名称
  • 编码转换器
  • Mysql面试知识点详解
  • 【MCP Node.js SDK 全栈进阶指南】中级篇(1):MCP动态服务器高级应用
  • 【MCP Node.js SDK 全栈进阶指南】初级篇(1):MCP开发环境搭建详解
  • Web前端开发技术——HTML5、CSS3、JavaScript
  • 深度剖析神经网络:从基础原理到面试要点(二)
  • 重学React(一):描述UI
  • SuperMap GIS基础产品FAQ集锦(20250421)
  • 1000 QPS 下 MySQL 性能瓶颈解决方案
  • Flutter IOS 真机 Widget 错误。Widget 安装后系统中没有
  • uniapp Vue2升级到Vue3,并发布到微信小程序的快捷方法
  • 用selenium4 webdriver + java 搭建并完成第一个自动化测试脚本
  • 什么是 金字塔缩放(Multi-scale Input)
  • iscsi服务端安装及配置
  • 【Unity笔记】Unity + OpenXR项目无法启动SteamVR的排查与解决全指南
  • Dataway在Spring Boot中的引入以及使用教程
  • OpenHarmony OS 5.0与Android 13显示框架对比
  • 经济日报刊文:如何破除“内卷式”竞争
  • 证券时报:金价再创历史新高,“避险”黄金不应异化为投机工具
  • 最大涨幅9800%!金价新高不断,引发期权“末日轮”效应,沪金期权多张合约大涨
  • 打造“旧书朋友圈”,“淘书乐”为旧书找“新朋友”
  • 直播中抢镜“甲亢哥”的翁东华卸任了!此前任文和友小龙虾公司董事
  • 88岁罗马教皇方济各突然去世,遗嘱内容对外公布