最近做的项目中要求低功耗,在单片机完成了手头上的工作之后,就进入低功耗模式,项目的需求是单片机进入低功耗模式的时候系统时钟从HSE切到HSI,但是在未进入低功耗模式之前引脚是什么状态,进入低功耗模式之后也不应该改变。可以通过RTC定时唤醒,或者接收到串口数据就唤醒,处理完数据后再进入stop模式。查询了一些资料之后,发现stop模式最符合项目需求。下面讲述一下什么是低功耗:
一、stm32支持三种低功耗模式,可以在低功耗,短启动,多种唤醒模式下寻找平衡。
1、SleepMode睡眠模式,只有CPU停止运行,所有的外设处于工作状态并且可以在发生中断/事件时唤醒CPU。 唤醒后程序会从刚刚停止的地方继续运行
2、StopMode停机模式,保持SRAM和寄存器内容不丢失,达到最低的电能消耗。停止所有内部1.8V部分的供电, PLL、 HSI的RC振荡器和HSE晶体振荡器被关闭,调压器可以被置于普通模式或低功耗模式。可以通过任一EXTI从停机模式中唤醒, EXTI信号可以是16个外部I/O口之一、 PVD的输出、 RTC闹钟或USB的唤醒信号。 唤醒后程序会从刚刚停止的地方继续运行
3、StandbyMode待机模式。最低的电能消耗。内部1.8V部分的供电被切断; PLL、 HSI的RC振荡器和HSE晶体振荡器关闭;SRAM和寄存器的内容将消失,但后备寄存器的内容仍然保留,待机电路仍工作。从待机模式退出的条件是: NRST上的外部复位信号、 IWDG复位、 WKUP引脚上的一个上升边沿或RTC的闹钟到时。唤醒后程序从头执行,相当于复位重启
二、低功耗模式基于HAL库的常用API
2.1睡眠模式SleepMode
- __HAL_RCC_PWR_CLK_ENABLE();//电源管理使能
- HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);//进入睡眠模式
2.2停机模式StopMode
- __HAL_RCC_PWR_CLK_ENABLE();//电源管理使能
- HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI);//进入停机模式
2.3 待机模式StandbyMode
- __HAL_RCC_PWR_CLK_ENABLE();//电源管理使能
- PWR_Check_Standby();//检查是否是待机模式
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);//清除唤醒标志
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);//清除待机标志
- __HAL_PWR_GET_FLAG(PWR_FLAG_SB);//获得待机模式标志
- HAL_PWR_EnterSTANDBYMode();//进入待机模式
以上相关描述参考https://blog.csdn.net/u010058695/article/details/100008613
三、Stop模式中遇到的一些问题及解决方法
1、没有配置好唤醒机制,导致进入stop模式后没能唤醒,导致无法识别到st-link,无法重新烧录程序。即使重新上电也不能识别到st-link。
我在这个问题上栽了跟头,因为单片机重新上电后依然不能识别到st-link,所以以为是单片机坏了,重新换了单片机再烧录同样的程序,结果问题还是一样,我开始意识到问题不是那么简单,上网找了一下资料,才知道是进入stop模式后不能唤醒,具体的做法有几种:
① 可以将单片机的NRST引脚引出来,外接复位键。(关于引脚查看可用ST官方软件STM32cubeMX,很方便)如图:把NRST引出来通过一个按键连接到GND,当进入STOP模式不能烧录程序的时候只需要在按下按键后,点击keil的

,然后松手即可。

② 通过ISP的方式下载程序,必须将boot0接高电平,boot1(PB2)接低电平,然后必须断电后重启,此时单片机会进入ISP模式,就可以通过串口1(一般单片机都是只有串口1才可下载程序)再用flymcu等软件烧入hex文件就可以了。
关于boot0和boot1,在每个stm32单片机都会有这两个引脚,这两个引脚在复位时的电平状态决定了芯片在复位后从哪个区域开始执行程序。
boot1=x boot0=0从用户闪存启动,这是正常的工作模式。
boot1=0 boot0=1从系统存储器启动(进入ISP模式)。
boot1=1 boot0=1从内置SRAM启动,这种模式可以用于调试。
如此一来,单片机无法进入正常的工作模式,就无法进行休眠,就可以通过ISP来下载程序。
③ 使用STlink烧写程序,STlink至少要接4根线(SWDIO、SWCLK、GND、SW-RST),一般的下载程序只需要前三根就可以了,但是以防出现休眠无法唤醒的情况,这时有复位键就可以将SWDIO和SWCLK重置,如果板子设计没有与SW-RST相对应的,此时需要把单片机上的NRST引出来接到SW-RST上。下载程序之前boot0接高电平,boot1不用管(也需要断电后重启)。
下载配置这里按如下配置,RESET那里HW RESET和SYSRESETREQ任选一个。
配置好之后load一个空程序即可,不要再烧一个休眠的程序了,之后就可以正常烧程序了。
以上解决方法参考https://blog.csdn.net/geekjin/article/details/79232405,总结就是复位NRST这个引脚是最简单的方法,以后做项目还是要提醒硬件工程师把这个引脚引出来。
2、项目需要单片机在进入stop 模式后过5秒钟就唤醒,实际上RTC闹钟中断也是挂在EXTI中断上的。我是用CubeMX配置的RTC,但是一直没有唤醒,后面终于找到问题所在了:

红色框框里的前三个应该配置为Enable,第四个应该配置为Disable,前三个是闹钟屏蔽星期,闹钟屏蔽小时,闹钟屏蔽分钟,如果不是这样配置的话,只能等到时间达到了设定好的某天某时某分某秒才能发生中断,那么只能一周唤醒一次了。如果是这样设置的话,就是一分钟唤醒一次,那么怎么才能5秒钟唤醒一次呢?我的做法是每次进入stop模式前就调用一次MX_RTC_Init()函数一次,因为我的时间是设置为x年x月x日星期x x时x分0秒,所以相当于每次进入stop模式前初始化一次RTC,5秒钟后就会发生闹钟中断。这种办法可能是比较笨的方法,但是好歹实现了这个功能哈哈
3、为了方便调试,我还配置了LED,每隔200ms闪烁一次,但是我发现从stop模式唤醒后灯的闪烁明显变得很慢,而且串口数据的接收和发送也不能完成,这是为什么呢?
原来进入stop模式后系统时钟默认切换到内部8M时钟,所以频率就会变慢了

我的解决方法是重新配置系统时钟:
| 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 |
|
4、接收到串口数据后怎么唤醒stop模式?
其实RTC闹钟中断唤醒stop模式也是因为闹钟事件是连接着外部中断线的,但是串口接收中断并不能唤醒stop模式啊,怎么办?

解决方法有两种,一种是在RX引脚上接上光耦连接到其他IO口上,把该IO口配置为外部中断,但是这种方案比较麻烦,所以可以采取第二种方案,在进入stop模式之前把RX引脚配置为外部中断模式,这样的话,RX引脚上有电平变化的时候就会发生外部中断,在服务函数中记得把RX引脚再配置为复用为UART的接收引脚。并且重新配置系统时钟,选择HSE为时钟源。这样就可以实现唤醒并接收数据了。但是因为第一次接收到串口数据的时候只能唤醒stop模式,并不能接收到数据,所以应该跟发送方约定好,一帧数据要发送两次。而且中间要有一定间隔,我的间隔是500ms。这样确实比较麻烦,但是暂时没有更好的办法。
5、串口接收引脚配置为外部中断引脚后还是没有正常接收到数据。在唤醒后延时1秒钟就可以接收到数据。
这是因为stop模式唤醒后,因为没有延时,很快又进入stop模式,这个时候第二帧数据还没到来,等到第二帧数据到来的时候处于stop模式中,这帧数据只能起到唤醒的作用,很快又进入了stop模式,变成一个恶性循环。
注意事项:
1.进入Stop模式后,任一外部中断皆可唤醒,也可以设置多个唤醒中断源。Standby唯有WKUP引脚的上升沿、RTC闹钟事件、NRST引脚上的外部复位、IWDG复位方能唤醒。
2.Standby模式的静态电流只有几微安(stop模式在30μA左右),尽可能使用Standby模式。
3.开机唤醒时有一定几率出现成功唤醒但进入某中断后陷入死循环状态,为了避免这种错误,关机之前务必:
1)清除所有中断标志位
EXTI_ClearITPendingBit(0x7FFFF);
RTC_ClearITPendingBit(0x07);
2)将除了开机唤醒之外的所有中断关闭
例如:
NVIC_InitStructure.NVIC_IRQChannel =TIM4_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelCmd= DISABLE;
NVIC_Init(&NVIC_InitStructure);
4.流程
1):使能PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
2):配置唤醒IO口、EXTI、NVIC
IO口配置为GPIO_Mode_IN_FLOATING模式。
3):关闭不用的中断,清除所有中断标志位(非常重要,如果不清除的话,Stop模式可能会因为不在预估范围内的中断而唤醒)
EXTI_ClearITPendingBit(0x7FFFF);
RTC_ClearITPendingBit(0x07);
4):进入停机/待机模式
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
或 PWR_EnterSTANDBYMode();
5):唤醒,关闭唤醒中断,重新配置系统时钟。
Stop模式唤醒之后会进入中断子函数,而后沿之前中断的位置继续执行。Standby模式并不会进入中断子函数,开机后系统自动复位。
5.低功耗配置
1)所有IO管脚,如果高阻状态端口是高电平,就设成上拉输入,如果高阻状态是低电平,设成下拉输入,如果高阻是中间状态,设成模拟输入。
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_All;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_Init(GPIOD,&GPIO_InitStructure);
2)两个晶振输入脚要remap成普通IO,使用内部晶振。
3)关闭所有外设
4)关闭jtag口,并设成普通IO;
以上就是我对stop模式和唤醒的总结,不正确的地方请大家斧正!
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?
我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'
我是Ruby的新手,但过去两周我一直在对Chef测试进行大量研究。该测试使用ChefSpec和Fauxhai,但它看起来不是很“像ruby”,我希望社区能给我一些编码风格的建议。有没有更好的方法来编写这样的嵌套循环?Recipe/foo/recipes/default.rbpackage"foo"doaction:installendRecipe/foo/spec/default_spec.rbrequire'chefspec'describe'foo::default'doplatforms={"debian"=>['6.0.5'],"ubuntu"=>['12.04','10.04
假设一个使用类变量的简单ruby程序,classHolder@@var=99defHolder.var=(val)@@var=valenddefvar@@varendend@@var="toplevelvariable"a=Holder.newputsa.var我猜结果应该是99,但输出不是99。我想知道为什么。由于类变量的范围是类,我假设@@var="toplevelvariable"行不会影响类中的变量。 最佳答案 @@var是Holder的类变量。而顶层的@@var不是Holder的同名类变量@@var,是你在创建类Obj