【极海APM32替代笔记】HAL库低功耗STOP停止模式的串口唤醒(解决进入以后立马唤醒、串口唤醒和回调无法一起使用、接收数据不全的问题)
【极海APM32替代笔记】HAL库低功耗STOP停止模式的串口唤醒(解决进入以后立马唤醒、串口唤醒和回调无法一起使用、接收数据不全的问题)
【STM32笔记】低功耗模式配置及避坑汇总
前文:
blog.csdn.net/weixin_53403301/article/details/128216064
【STM32笔记】HAL库低功耗模式配置(ADC唤醒无法使用、低功耗模式无法烧录解决方案)
低功耗模式如图所示
停止模式有三种 分别是0 1 2
其中 0 1可以由串口唤醒
2只能由LPUART唤醒
在手册里可以查到
进入也很简单:
/*!* @brief 进入低功耗模式 ** @param [in] mode_flag: 模式标志* 0/大于4 不进入任何模式,1 进入睡眠,2 进入停止,3 进入待机,4 关机* [in] WakeUpPinPolarity: 待机模式下WKUP唤醒引脚极性配置,其他模式无用** @return None*/
void Enter_Low_PWR(uint8_t mode_flag,uint32_t WakeUpPinPolarity)
{ __HAL_RCC_PWR_CLK_ENABLE();switch(mode_flag){case 0:{printf("[INFO] 不进入低功耗模式\n");break;}case 1:{printf("[INFO] 进入睡眠模式\n");delay_ms(10); //消抖__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);break;}case 2:{printf("[INFO] 进入停止模式\n");delay_ms(10); //消抖__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);break;}case 3:{printf("[INFO] 三秒后进入待机模式\n");delay_ms(3000);printf("[INFO] 进入待机模式\n");HAL_PWR_EnableWakeUpPin(WakeUpPinPolarity);delay_ms(10); //消抖__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);HAL_PWR_EnterSTANDBYMode();break;}case 4:{printf("[INFO] 三秒后进入关机模式\n");delay_ms(3000);printf("[INFO] 进入关机模式\n");HAL_PWR_EnableWakeUpPin(WakeUpPinPolarity);delay_ms(10); //消抖__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);HAL_PWREx_EnterSHUTDOWNMode();break;}default:{printf("[INFO] 不进入低功耗模式\n");break;}}
}
要进入停止2模式则需要在pwr_ex.c中配置
HAL_PWREx_EnterSTOP2Mode();函数
其中
HAL_PWR_EnterSTOPMode中的PWR_MAINREGULATOR_ON、PWR_LOWPOWERREGULATOR_ON分别是开启稳压器和关闭稳压器 分别对应STOP 0和1
在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其 1.8V 区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。停止模式可以由任意一个外部中断(EXTI)唤醒,在停止模式中可以选择电压调节器为开模式或低功耗模式。
特性和说明:调压器低功耗模式: 在停止模式下调压器可工作在正常模式或低功耗模式,可进一步降低功耗。
进入方式: 内核寄存器的 SLEEPDEEP=1,PWR_CR 寄存器中的 PDDS=0,然后调用 WFI 或 WFE 指令即可进入停止模式;PWR_CR 寄存器的 LPDS=0 时,调压器工作在正常模式,LPDS=1 时工作在低功耗模式。
唤醒方式: 如果是使用 WFI 指令睡眠的,可使用任意 EXTI 线的中断唤醒;如果是使用 WFE 指令睡眠的,可使用任意配置为事件模式的 EXTI 线事件唤醒。
停止时: 内核停止,片上外设也停止。这个状态会保留停止前的内核寄存器、内存的数据。
唤醒延迟: 基础延迟为 HSI 振荡器的启动时间,若调压器工作在低功耗模式,还需要加上调压器从低功耗切换至正常模式下的时间。
唤醒后: 若由中断唤醒,先进入中断,退出中断服务程序后,接着执行 WFI 指令后的程序;若由事件唤醒,直接接着执行 WFE 后的程序。唤醒后,STM32 会使用 HSI 作为系统时钟。
只能由外部中断唤醒 唤醒后需要重新使能时钟(SystemClock_Config();)
建议将一条外部中断线专门作为唤醒中断,执行中断后进入回调进行时钟使能
停止模式0和1由PWR_MAINREGULATOR_ON和PWR_LOWPOWERREGULATOR_ON两个变量确定
停止模式0和1可以被串口 I2C等设备唤醒(具体看手册)
停止模式2则在pwr_ex.c中进入
停止模式2 只能被特定器件(如LPUART等在内部与EXTI有链接的器件)唤醒
若要配置UART唤醒 则需要:
/*!* @brief 配置串口在停止模式下的唤醒 ** @param [in] huart: UART_HandleTypeDef类型的器件* [in] EnableNotDisable: 使能或者关闭** @return None*/
void Ctrl_UART_StopMode_WakeUp(UART_HandleTypeDef *huart,bool EnableNotDisable)
{ if(EnableNotDisable){__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); //保留唤醒用的HSI线 串口初始化时钟也必须要配置为HSIUART_WakeUpTypeDef UART_WakeUpStruct={0};UART_WakeUpStruct.WakeUpEvent=UART_WAKEUP_ON_READDATA_NONEMPTY; //接收数据不为空时唤醒HAL_UARTEx_StopModeWakeUpSourceConfig(huart,UART_WakeUpStruct);__HAL_UART_ENABLE_IT(&huart2,UART_IT_WUF); //开启唤醒中断HAL_UARTEx_EnableStopMode(huart); //开启模式}else{__HAL_UART_DISABLE_IT(&huart2,UART_IT_WUF); //关闭唤醒中断HAL_UARTEx_DisableStopMode(huart); //关闭模式}
}
配置为接收数据就唤醒
若要使用 则UART必须为HSI或MSI时钟 配置太麻烦 所以我建议直接在HAL里面配置
串口回调一般是:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart==&huart2){ HAL_UART_Transmit(&huart2,&RxBuffer,1,0xFFFF);HAL_UART_Receive_IT(&huart2,&RxBuffer,1);}if(huart==&huart4){ HAL_UART_Transmit(&huart4,&RxBuffer,1,0xFFFF);HAL_UART_Receive_IT(&huart4,&RxBuffer,1);}
}
接收数据后发送数据
而唤醒回调则是:
void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart)
{if(huart==&huart2){ __HAL_RCC_PWR_CLK_ENABLE();SystemClock_Config(); Ctrl_UART_StopMode_WakeUp(huart,false);}
}
进入以后立马唤醒
若是串口悬空 或硬件设计问题 串口数据不定 则可能进入以后立马被唤醒
在外部硬件上加下拉 或者软件配置下拉(或上拉)即可 不过下拉更省电
串口唤醒和回调无法一起使用的问题
在调试时 发现串口唤醒和回调无法一起使用 进入了回调以后就退出了 不会进入串口唤醒
其实就是
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); //保留唤醒用的HSI线 串口初始化时钟也必须要配置为HSI
的问题
若不使用这个语句 虽然串口可以用 也能接收数据并返回 但是进不了唤醒回调
其实就是因为时序被改变了
进入低功耗以后 接收数据唤醒 则先进入接收回调 然后发一次数据 但不会进行唤醒 因为时序有问题 mcu认为接收的数据不正常
保留这个语句以后就好了
另外 每次进入低功耗前 都要先调用
Ctrl_UART_StopMode_WakeUp(huart,true);
语句 否则无法正常唤醒 也不能再次进入低功耗模式
为了避免出错 每次唤醒以后都应该清空调唤醒中断
STOP模式会关闭时钟 所以建议是回调以后就初始化时钟一次
Ctrl_UART_StopMode_WakeUp(&huart2,true);
Enter_Low_PWR(2,0);
LPUART的配置同理 完全一模一样的语句
串口回调接收数不全的问题
在前文中 我们将唤醒后的时钟初始化写进了唤醒回调中
如果没有特别要求 这样写确实挺方便的
RTC唤醒后的配置就可以这样来写
但是 在调试时发现 如果发送长字符 则可能导致接收数据不全的问题
我用的波特率是115200 在没有进入低功耗时 发送连续几段012345689 接收到数组内是正常的
我的回调函数为:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart==&huart2){
// HAL_UART_Transmit(&huart2,&(RxBuffer[RxFlag]),1,0xFFFF);RxFlag++;HAL_UART_Receive_IT(&huart2,&(RxBuffer[RxFlag]),1); }
}
但是 在进入低功耗后唤醒 buf里面只能接收到前两个字符01 然后延后大约10个字符后继续接收 总数少了约10个字符
经过调试发现 其执行的顺序是先开启两次串口回调 接收到第一个字符 然后进入唤醒回调 在唤醒回调中 初始化时间较长 所以没有触发接收回调函数 导致丢失字符
调整后 唤醒回调改成:
void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart)
{}
同时把退出低功耗后的初始化配置放在退出低功耗以后(不采用中断回调函数来完成)
printf("[INFO] 进入停止模式\n");
delay_ms(10); //消抖
Ctrl_UART_StopMode_WakeUp(&huart2,true);
Ctrl_RTC_WakeUp(5000,RTC_WAKEUPCLOCK_RTCCLK_DIV16,true);
PWR_Device_Init(false);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
__HAL_RCC_PWR_CLK_ENABLE();
SystemClock_Config();
Ctrl_UART_StopMode_WakeUp(&huart2,false);
Ctrl_RTC_WakeUp(0,0,false);
PWR_Device_Init(true);
这样的话 就不会出现问题了
说到底 就是唤醒中断优先级高(且无法配置) 触发了这个中断 低级的串口接收中断就无法触发了
在实际应用中 也应保证中断时间越短越好 以免干扰到其他中断
相关文章:

【极海APM32替代笔记】HAL库低功耗STOP停止模式的串口唤醒(解决进入以后立马唤醒、串口唤醒和回调无法一起使用、接收数据不全的问题)
【极海APM32替代笔记】HAL库低功耗STOP停止模式的串口唤醒(解决进入以后立马唤醒、串口唤醒和回调无法一起使用、接收数据不全的问题) 【STM32笔记】低功耗模式配置及避坑汇总 前文: blog.csdn.net/weixin_53403301/article/details/128216…...

Python类变量和实例变量(类属性和实例属性)
无论是类属性还是类方法,都无法像普通变量或者函数那样,在类的外部直接使用它们。我们可以将类看做一个独立的空间,则类属性其实就是在类体中定义的变量,类方法是在类体中定义的函数。 在类体中,根据变量定义的位置不…...

Glide加载图片
使用Glide加载图片,默认情况下在内存中缓存该图片。这样的情况下如果我们保存头像在某个路径,当再次更换头像时可能由于缓存问题,UI上更新的不及时。 默认加载图片方式: Glide.with(context).load(coverPath).error(R.drawable.a…...

有关时间复杂度和空间复杂度的练习
目录 一、消失的数字 二、轮转数组 三、 单选题 一、消失的数字 数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在 O(n) 时间内完成吗? 注意:本题相对书上原题稍作改动 示例 1: 输入…...

linux服务器nfs数据挂载
参考:https://blog.csdn.net/qq_43721935/article/details/119889841?from_wecom1 1、NFS 介绍 NFS 即网络文件系统(Network File-System),可以通过网络让不同机器、不同系统之间可以实现文件共享。通过 NFS,可以访问…...

Python 自动化测试必会技能板块—unittest框架
说到 Python 的单元测试框架,想必接触过 Python 的朋友脑袋里第一个想到的就是 unittest。的确,作为 Python 的标准库,它很优秀,并被广泛应用于各个项目。但其实在 Python 众多项目中,主流的单元测试框架远不止这一个。…...

mysql存储引擎、事务、索引
目录MySQL进阶存储引擎什么是存储引擎常用存储引擎事务什么是事务怎么理解提交事务 和回滚事务事务特性事务的隔离级别索引什么是索引索引的实现原理什么条件下,我们会考虑给字段添加索引呢?什么条件下,索引会失效?索引分类MySQL进阶 存储引…...

毕业论文图片格式、分辨率选择及高质量Word转PDF方法
已知1:毕业论文盲评通常需要提交PDF文件。 已知2:PDF文件太大可能会导致翻页卡顿以及上传盲评网站失败。 已知3:Word转PDF方法不当可能会导致图像模糊。 已知4:打印机分辨率通常为300dpi。 问题1:论文插图分辨率设置…...

华为外包测试2年,不甘被替换,168天的学习转岗成正式员工
我25岁的时候,华为外包测试,薪资13.5k,人在深圳。 内卷什么的就不说了,而且人在外包那些高级精英年薪大几十的咱也接触不到,就说说外包吧。假设以我为界限,25岁一线城市13.5k,那22-24大部分情况…...

简单的C++:【运算符重载】新手易学
学过C语言的同志们应该都知道位运算符>> 和 << (右移左移),但是这两个运算符在C中还是我们的输入和输出流操作符,那么这是为什么呢?,了解完本篇文章之后,我们再来回答这个问题。 C为…...

NPE:记一次脑残NPE的排查过程
目录 碎碎念: 如下这行报NPE: 排查过程: 解解方案: 小结: 空指针出现的几种情况: 如何从根源避免空指针: 赋值时自动拆箱出现空指针: 1、变量赋值自动拆箱出现的空指针 2、…...

canvas样式与颜色,字体,图片,状态,形变
色彩 fillStyle color 设置图形的填充颜色。 strokeStyle color 设置图形轮廓的颜色。 备注: 一旦您设置了 strokeStyle 或者 fillStyle 的值,那么这个新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,你需要重新设置…...

重识html
html 重识html 万维网用url统一资源定位符标识分布因特网上的各种文档 各种概念 URL: 统一资源定位器 它是WWW的统一资源定位标志,就是指网络地址 在WWW上,每一信息资源都有统一的且在网上唯一的地址 网页: 由文字 图片 视频 音乐各种元素排列组…...

Redis:缓存一致性问题(缓存更新策略)
Redis缓存的一致性1. 缓存1.1 缓存的作用:1.2 缓存的成本:2. 缓存模型3. 缓存一致性问题3.1 引入3.2 解决(1) 先更新数据库,再手动删除缓存(2) 使用事务保证原子性(3) 以Redis中的TTL为兜底3.3 案例:商铺信息查询和更新(1) 查询商…...

spring之声明式事务开发
文章目录一、声明式事务之全注解式开发1、新建springConfig类2、测试程序3、测试结果二、声明式事务之XML实现方式1、配置步骤2、测试程序3、运行结果附一、声明式事务之全注解式开发 基于之前的银行转账系统,将spring.xml配置文件嘎掉,变成全注解式开发…...

2023美赛参赛经历分享
今天早上登录MCM: The Mathematical Contest in Modeling (comap.com)发现论文提交已经显示Received。虽然这几天连连有开学恶补的期末考试,但还是忙里偷闲趁着新鲜写一篇关于美赛的参赛个人感受。跟我一起打这次美赛的都是软件等专业的hxd,他们之前没有…...

Elasticsearch在Linux中的单节点部署和集群部署
目录一、Elasticsearch简介二、Linux单节点部署1、软件下载解压2、创建用户3、修改配置文件4、切换到刚刚创建的用户启动软件5、测试三、Linux集群配置1、拷贝文件2、修改配置文件3、分别修改文件所有者4、启动三个软件5、测试四、问题总结1、在elasticsearch启动时如果报错内存…...

Scala的变量声明
文章目录变量声明(一)简单说明(二)利用val声明变量1,声明方式2,案例演示(三)利用var声明变量1,声明方式2,案例演示(四)换行输入语句&a…...

面试了字节、美团、腾讯等30几家公司后,才知道软件测试面试全是这个套路......
一、Linux系统应用和环境配置: 1、Linux系统的操作命令给我说10个,一般用什么工具远程连接Linux服务器? 2、Linux中的日志存储在哪里?怎么查看日志内容? 3、Linux中top和ps命令的区别? 4、Linux命令运行…...

Anaconda环境配置
1.进入清华大学镜像网站Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror,下载稳定版Anaconda3-5.2.0,如下图。2.放到整理好的文件夹中,双击安装包进行安装。3.安装过程中需要改变的默认值如下ÿ…...
Markdown编辑器使用方法
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…...

“双碳”目标下二氧化碳地质封存技术应用前景及模型构建实践方法与讨论
我国二氧化碳地质封存技术起步较晚,目前仍没有一套相对完整的行业规范;且就该技术而言,涉及环节众多,理论相对复杂,对于行业的新入局者不太友好。因此,结合时代背景,我们首次尝试对二氧化碳地质…...

算法笔记(十二)—— Manacher算法(回文子串)
计算字符串内的最大回文子串,常用的暴力扩散在应对长度为偶数的回文时会遇到一些问题。 Manacher基础:对字符串进行填充,在字符串开头结尾以及字符间填充‘#’,以来应对偶数回文时的问题。(这是采用暴力扩再除2&#x…...

【数据结构】顺序表和链表的区别和联系(详解)
顺序表和链表的区别(详解) 文章目录顺序表和链表的区别(详解)前言一、顺序表和链表的关系二、顺序表1.优点2.缺点三、链表1.优点2.缺点四、区别表格总结前言 本文给大家介绍顺序表和链表的各自的优缺点和区别与联系,结…...

【Linux操作系统】【综合实验三 用户帐号、文件系统与系统安全管理】【更新中】
文章目录一、实验目的二、实验要求三、实验内容四、实验报告要求一、实验目的 要求掌握Linux系统用户的创建、删除与管理操作;熟悉Linux文件系统的管理模式,学会创建用户文件系统并装载和卸载文件系统;掌握超级用户的管理方式与权限…...

华为OD机试真题 用 C++ 实现 - 整数分解 | 多看题,提高通过率
最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…...

Java集合(一)---List和set
1.Java集合有哪些?集合类型主要有3种:set(集)、list(列表)和map(映射)Map接口和Collection接口是所有集合框架的父接口:1. Collection接口的子接口包括:Set接口和List接口2. Map接口的实现类主要有…...

手撸一个Table组件(Table组件不过如此)
一、前言 手写Table组件这个文章我一直都想写,今天终于得空来写它了。小编认为Table组件是组件库里"较为复杂"的一个组件,因为它的扩展性非常强,并且它的基础样式如何去写都非常考究,那么今天我就带大家来实现一个基础…...

Python|Leetcode刷题日寄Part01
Python|Leetcode刷题日寄Part0101:两数之和02:无重复字符的最长子串03:两数相加04:反转链表05:有效的括号06:回文数07:删除有序数组中的重复项08:删除链表的倒数第N个结点09…...

微信小程序更改头像昵称
背景 前面写了一篇关于小程序头像昵称获取更改的方案,有很多小伙伴私信我发一个整体的逻辑思路! 解决思路 前面的这篇文章中我们给出了页面中获取头像昵称的代码: <view class"headInfo" data-weui-theme"{{theme}}&qu…...