【STM32笔记】低功耗模式下GPIO、外设、时钟省电配置避坑

news2024/11/18 7:45:43

【STM32笔记】低功耗模式下GPIO、外设、时钟省电配置避坑

前文:
blog.csdn.net/weixin_53403301/article/details/128216064
【STM32笔记】HAL库低功耗模式配置(ADC唤醒无法使用、低功耗模式无法烧录解决方案)

blog.csdn.net/weixin_53403301/article/details/129055530
【STM32笔记】低功耗模式下GPIO省电配置避坑实验(闲置引脚配置为模拟输入其实更耗电)

在这里插入图片描述
在进入低功耗模式前 可以通过降低时钟频率 关闭GPIO口(通常是配置为模拟输入 或降低GPIO时钟) 以及关闭不需要的外设来降低功耗(尤其是在SLEEP、STOP模式)

时钟的话 如果用不上 或者进入STOP等模式 则也不需要配置 进入模式时 时钟本身就会被配置

关闭外设的函数在进入低功耗的前一步执行 相关唤醒配置需要在关闭外设前执行 且要注意 不能关闭用于唤醒的外设及其GPIO口

而用不到的外设和对应的GPIO口 建议同时关闭

以我的为例:

/*!
 * @brief       	所有外设初始化配置,根据使用需求来写
 *
 * @param 	[in]	EnableNotDisable: 使能或者关闭
 *								true: 进行初始化外设(不包含时钟初始化)
 *								false: 或者关闭所有外设,所有GPIO配置为无上拉下拉且模拟输入,仅保留系统时钟和系统所需的GPIO口复用
 *								该函数在进入低功耗前调用(false)
 *								建议在进入该函数前(false)先配置用于唤醒的外设 如指定UART或RTC作为唤醒使用 然后再调用该函数 且不能关闭有唤醒功能的外设
 *								若用于唤醒后的初始化,则建议先初始化时钟,再执行该函数的初始化(true)
 *								在休眠期间使用的外设,不要关闭,也不要关闭GPIO等;相反,外设和GPIO等建议同时关闭(避免出现bug,并且也省电)
 *								未关闭,但唤醒时重复初始化外设并不受影响
 *								若未关闭的外设在运行中改变了初始化值,则建议不在唤醒时运行该初始化(前提是外设的GPIO等也没有作改动)
 *								若需要在初始化后更改初始化值,则建议要么不进行初始化且不关闭(也包括GPIO等),或重新设置新值
 *
 * @return				None
 */
void PWR_Device_Init(bool EnableNotDisable)
{
	if(EnableNotDisable)
	{
		//这里是系统最初的初始化值
		GPIO_Reset_Init(false);  //重置GPIO		
		MX_GPIO_Init();
		MX_USART2_UART_Init();
		MX_UART4_Init();
		MX_ADC1_Init();
		MX_ADC2_Init();
		MX_TIM6_Init();
		MX_RTC_Init();
		MX_ADC3_Init();
		
		//这里放初始化后还要更改的配置,若要重新初始化,建议先运行外设DeInit
//		HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8,GPIO_PIN_SET);
//		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,GPIO_PIN_SET);
	}
	else
	{
		HAL_ADC_DeInit(&hadc1);
		HAL_ADC_DeInit(&hadc2);
		HAL_ADC_DeInit(&hadc3);
//		HAL_UART_DeInit(&huart2);		//唤醒用的串口 最好不要关闭:若不用于唤醒 则可以关闭 GPIO等同步关闭;若用于唤醒 则不能关闭 GPIO等也不能关闭
		HAL_UART_DeInit(&huart4);
		HAL_TIM_Base_DeInit(&htim6);
//		HAL_RTC_DeInit(&hrtc);		//唤醒用的RTC 最好不要关闭		

		GPIO_Reset_Init(true);  //GPIO配置为复用
	}
}

  •  						true: 进行初始化外设(不包含时钟初始化)
    
  •  						false: 或者关闭所有外设,所有GPIO配置为无上拉下拉且模拟输入,仅保留系统时钟和系统所需的GPIO口复用
    
  •  						该函数在进入低功耗前调用(false)
    
  •  						建议在进入该函数前(false)先配置用于唤醒的外设 如指定UART或RTC作为唤醒使用 然后再调用该函数 且不能关闭有唤醒功能的外设
    
  •  						若用于唤醒后的初始化,则建议先初始化时钟,再执行该函数的初始化(true)
    
  •  						在休眠期间使用的外设,不要关闭,也不要关闭GPIO等;相反,外设和GPIO等建议同时关闭(避免出现bug,并且也省电)
    
  •  						未关闭,但唤醒时重复初始化外设并不受影响
    
  •  						若未关闭的外设在运行中改变了初始化值,则建议不在唤醒时运行该初始化(前提是外设的GPIO等也没有作改动)
    
  •  						若需要在初始化后更改初始化值,则建议要么不进行初始化且不关闭(也包括GPIO等),或重新设置新值
    

GPIO配置也是个坑
(相关配置及唤醒功能等 见前文)

/*!
 * @brief       	重置GPIO(都会进行),或再将除外部高低速晶振复用、SWCLK、SWDIO复用的所有GPIO配置为模拟输入(false)
 *								注意:用于串口唤醒等的引脚,不可配置为模拟输入,也不可关闭
 *								在进行GPIO初始化前,先将GPIO_DeInit,但是不做也不影响,不过还是建议跑一下
 *								以优先级顺序来看:
 *								如果这一组GPIO都没用到过 那么直接不开启时钟就最省电
 *								如果这一组GPIO有引脚用过了 时钟不能关 那么就将用过的引脚配置为模拟输入
 *								切记!!!:
 *								不要将没用过的引脚配置为模拟输入 耗电量其实会稍微增加一点!
 *								不要将没用过的GPIO时钟打开以后再配置为模拟输入 耗电量会增加很多 就算配置后再关时钟也没用!
 *								尽量不要勾选CubeMX中的配置闲置引脚为模拟输入的选项 没用到的时钟还开启了会增加很多耗电
 *								低功耗模式配置:
 *								在进入STOP模式时 GPIO会保留原本的状态 所以把开启后不需要再保留的GPIO配置为模拟输入确实省电 时钟的话不用的肯定关 其他的反正都会关(除了保留的时钟)
 *								在进入SLEEP模式时 时钟并不会关闭 所以时钟应手动关闭 且将开启后的GPIO配置为模拟输入
 *								待机模式和关机模式就更不用在意GPIO口耗电了
 *								https://blog.csdn.net/weixin_53403301/article/details/129055530
 *
 * @param 	[in]	EnableNotDisable: 使所有GPIO变成模拟输入或不进行模拟配置
 *
 * @return				None
 */
void GPIO_Reset_Init(bool EnableNotDisable)
{
//	HAL_GPIO_DeInit(GPIOA,GPIO_PIN_2|GPIO_PIN_3);		//用于串口唤醒的引脚 不可变动
	
	HAL_GPIO_DeInit(GPIOA,GPIO_PIN_0|GPIO_PIN_1
												|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
												|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
												|GPIO_PIN_12|GPIO_PIN_15);
	
	HAL_GPIO_DeInit(GPIOB,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
												|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
												|GPIO_PIN_15|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5
												|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9);
	
	HAL_GPIO_DeInit(GPIOC,GPIO_PIN_13|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2
												|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6
												|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
												|GPIO_PIN_11|GPIO_PIN_12);
	
	HAL_GPIO_DeInit(GPIOD,GPIO_PIN_2);
	
	HAL_GPIO_DeInit(GPIOH,GPIO_PIN_3);
	
	if(EnableNotDisable)
	{
		GPIO_InitTypeDef GPIO_InitStruct = {0};

		/* GPIO Ports Clock Enable */
		__HAL_RCC_GPIOC_CLK_ENABLE();
		__HAL_RCC_GPIOH_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_GPIOD_CLK_ENABLE();

		/*Configure GPIO pins : PC13 PC0 PC1 PC2
														 PC3 PC4 PC5 PC6
														 PC7 PC8 PC9 PC10
														 PC11 PC12 */
		GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2
														|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6
														|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
														|GPIO_PIN_11|GPIO_PIN_12;
		GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

		/*Configure GPIO pins : PA0 PA1 PA2 PA3
														 PA4 PA5 PA6 PA7
														 PA8 PA9 PA10 PA11
														 PA12 PA15 */
		GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1
														|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
														|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
														|GPIO_PIN_12|GPIO_PIN_15;
		GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		
//		//用于串口唤醒的 不可变动
//		GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
//		GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
//		GPIO_InitStruct.Pull = GPIO_NOPULL;
//		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		
		/*Configure GPIO pins : PB0 PB1 PB2 PB10
														 PB11 PB12 PB13 PB14
														 PB15 PB3 PB4 PB5
														 PB6 PB7 PB8 PB9 */
		GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
														|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
														|GPIO_PIN_15|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5
														|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
		GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		/*Configure GPIO pin : PD2 */
		GPIO_InitStruct.Pin = GPIO_PIN_2;
		GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

		/*Configure GPIO pin : PH3 */
		GPIO_InitStruct.Pin = GPIO_PIN_3;
		GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
	}
}

  •  						注意:用于串口唤醒等的引脚,不可配置为模拟输入,也不可关闭
    
  •  						在进行GPIO初始化前,先将GPIO_DeInit,但是不做也不影响,不过还是建议跑一下
    
  •  						以优先级顺序来看:
    
  •  						如果这一组GPIO都没用到过 那么直接不开启时钟就最省电
    
  •  						如果这一组GPIO有引脚用过了 时钟不能关 那么就将用过的引脚配置为模拟输入
    
  •  						切记!!!:
    
  •  						不要将没用过的引脚配置为模拟输入 耗电量其实会稍微增加一点!
    
  •  						不要将没用过的GPIO时钟打开以后再配置为模拟输入 耗电量会增加很多 就算配置后再关时钟也没用!
    
  •  						尽量不要勾选CubeMX中的配置闲置引脚为模拟输入的选项 没用到的时钟还开启了会增加很多耗电
    
  •  						低功耗模式配置:
    
  •  						在进入STOP模式时 GPIO会保留原本的状态 所以把开启后不需要再保留的GPIO配置为模拟输入确实省电 时钟的话不用的肯定关 其他的反正都会关(除了保留的时钟)
    
  •  						在进入SLEEP模式时 时钟并不会关闭 所以时钟应手动关闭 且将开启后的GPIO配置为模拟输入
    
  •  						待机模式和关机模式就更不用在意GPIO口耗电了
    

而低功耗进入则改成了:
(相关配置及唤醒功能等 见前文)

printf("[INFO] 进入停止模式\n");
delay_ms(10);  //消抖
PWR_Device_Init(false);			
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
break;

同样 在唤醒后 唤醒回调里面也得先配置时钟再进行外设初始化

void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart)
{
	if(huart==&huart2)
  {		
		__HAL_RCC_PWR_CLK_ENABLE();
		HAL_Init();
		SystemClock_Config();		
		Ctrl_UART_StopMode_WakeUp(huart,false);
		PWR_Device_Init(true);
  }
}

void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
	__HAL_RCC_PWR_CLK_ENABLE();
	HAL_Init();
	SystemClock_Config();
	Ctrl_RTC_WakeUp(0,0,false);
	PWR_Device_Init(true);
}

不过 HAL_Init可以省略 但是为了避免出现bug 还是放在这里.

调用的时候:

	Ctrl_UART_StopMode_WakeUp(&huart2,true);
	Ctrl_RTC_WakeUp(20000,RTC_WAKEUPCLOCK_RTCCLK_DIV16,true);
	Enter_Low_PWR(2,0);

先配置唤醒用的功能 再进入低功耗

当然 唤醒用的外设也需要在最开始进行初始化配置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/349893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最强找茬小程序

文章目录准备工作环境要求安装步骤效果展示源码下载最强找茬小程序,支持好友对战 准备工作 准备一个Linux系统的云服务器 centos7或ubuntu 安装宝塔面板(不是必需的,建议安装这个) 买一个域名,并配置ssl证书&#x…

NX二次开发编译时dll自动数字签名及拷贝

前言 在UG5.0开始,所有基于UG二次开发的DLL都要“签名”后才能被客户端上正版的NX调用。 一、基于C# 开发签名 1、添加资源文件 (1)项目类库上右键–>属性–>资源–>添加资源右边小三角–>添加现有文件–>切换到UG安装目录下…

Java SSM 笔记(一)重置版

Spring核心技术 **前置课程要求:**请各位小伙伴先完成《JavaWeb》篇、《Java 9-17新特性》篇视频教程之后,再来观看此教程。 **建议:**对Java开发还不是很熟悉的同学,最好先花费半个月到一个月时间大量地去编写小项目&#xff0…

Source lnsight工具的简单使用

多文件编程推荐用Source lnsight工具来进行编写 一、Source lnsight工具的简单使用 1、在桌面上新建一个文件夹factory,在文件夹里新建一个cat.c文件和si文件夹 2、打开Source lnsight工具,点击上方Project--->New Project 3、把文件夹factory中si文…

2023年初级会计职称考试《经济法基础》大纲变动内容

整体变动:2023年度考试大纲主要作了以下调整:1. 第四章中增加了增值税出口退税和地方教育附加相关内容;2. 第五章中增加了企业重组业务企业所得税处理,企业所得税特别纳税调整和纳税电报表相关内容;3. 第六章中增加了印花税相关内容。具体变动:第一章 总论无变化第二…

QML矩形(Rectangle)

Rectangle 用于绘制矩形 常见的属性: 填充颜色:纯色:color 渐变 :Gradient类 渐变的优先级大于纯色Gradient(渐变色): 渐变由多种颜色定义,这些颜色将无缝混合&#xff0c…

【前端基础问题】浏览器调起桌面通知功能 Notification

浏览器调起桌面通知功能 Notification一、Notification二、注意事项三、使用步骤1、向用户发起权限请求2、调用 Notification API 进行推送消息四、完整代码五、效果一、Notification Notifications API 允许网页或应用程序在系统级别发送在页面外部显示的通知;这样即使应用程序…

【Servlet+Jsp+Mybatis+Maven】WEB图书馆管理系统

web图书馆管理系统一、绪论二、流程和其页面展示效果流程页面效果项目结构三、具体实现第一步:备数据库表第二步:编写登录前端代码第三步:利用过滤器处理安全问题第四步:控制层去实现相关调用第五步:实现持久化层与数据…

教你如何搭建人事OA-薪资管理系统,demo可分享

1、简介1.1、案例简介本文将介绍,如何搭建人事OA-薪资管理。1.2、应用场景根据设置薪资基础及考勤和绩效的数据计算得到各个员工工资详情。2、设置方法2.1、表单搭建1)新建表单【工资表】,字段设置如下;名称类型名称类型人员资料分…

一款私有化部署的企业级在线文档和知识库

项目介绍基础说明:无忧企业文档是JVS体系下的一款企业协同在线文档,主要服务客群为企业用户,解决企业内部文档编辑、知识沉淀、知识协同等痛点。项目主要采用Java开发,基础框架采用JVS(spring cloudVue)适用…

基于微信小程序的一款小程序版知乎

从零开始开发的一款小程序,所以没有使用任何框架及UI库,记录一下本次开发中踩过的坑吧~展示效果(界面样式设计与交互来自iOS 4.8.0版本知乎App):项目地址:https://download.csdn.net一、开始前的准备申请账号:根据小程…

钉钉配置事件订阅(Python)

钉钉配置事件订阅 0.需求分析 需要实现钉钉企业通讯录同步至企业微信通讯录,这就需要用到钉钉的事件与回调 1.配置应用 登陆开放平台 https://open-dev.dingtalk.com/去企业内部开发里面,先创建个应用,后面都借用这个应用来调接口 创建完…

自定义分库分表组件(实现分库分表的组件)——java

系列文章目录 文章目录系列文章目录前言一、所需技术二、技术总结1. ThreadLocal2.HashMap三、实现1、定义路由注解自定义注解格式要求元注解: 用于描述注解的注解在程序使用(解析)注解:获取注解中定义的属性值小例子:注解定义一个简单的测试…

AI算法创新赛-人车目标检测竞赛总结03

团队简介AI0000032 团队成员均为从事计算机视觉领域的企业员工,热爱技术,勇于挑战,致力于更通用目标检测算法的研究与落地。团队由三人组成,队长何正海 主要负责整体方案设计与模型的量化工作,余洋主要负责模型训练与调…

YOLOV5输出的txt里面有什么猫腻(用于图像分类竞赛中提升图像信息密度)

背景概括: kaggle最近举办了一场医学乳腺癌检测的比赛(图像分类) 比赛官网地址 给的数据是dcm的专业的医学格式,自己通过DICOM库转为png后,发现该图像胸部不同的患者乳腺大小不一,简言之乳腺的CT有效图在…

MySQL性能调优与设计——MySQL中的索引

MySQL中的索引 InnoDB存储引擎支持以下几种常见索引:B树索引、全文索引、哈希索引,其中比较关键的是B树索引。 B树索引 InnoDB中的索引自然也是按照B树来组织的,B树的叶子节点用来存放数据。 聚集索引/聚簇索引 InnoDB中使用了聚集索引&…

LeetCode 141. 环形链表

原题链接 难度:easy\color{Green}{easy}easy 题目描述 给你一个链表的头节点 headheadhead ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 nextnextnext 指针再次到达,则链表中存在环。 为了表示给定链表中的…

python编写webapi读取mdb数据使用json格式响应客户端请求

想做个自动应答机器人,通过webapi提供服务,原理:判断关键字,到数据库查询相关内容,以json格式反馈给客户端。 1、创建autoreply数据库,创建reply表,表中包含kename(短文本&#xff…

积水在线监测仪——积水点、易涝点水位监测设备

一、设备概述 积水在线监测仪是一款用于城市积水点、易涝点等场景的水位监测设备,设备采用电池供电,无需另外供电,安装方便,使用简单。可以时监测水点、易涝点水位情况,当水位数据超过阈值后触发告警上传,…

MybatisPlus实现分页效果并解决错误:cant found IPage for args!

前言 早就知道MybatisPlus对分页进行了处理,但是一直没有实战用过,用的是自己封装的一个分页组件,虽不说麻烦吧,但是也不是特别简单。 写起来还是比较复杂,但是最近这个组件有了点小小的bug,我决定是时候…