前言
这几天对公司的一个生产小工具进行了升级,由于准备将小工具发给客户使用,因此需要制作的精良一些,于是便卡在低功耗上。
问题描述
程序是公司前辈几年前写的,在stm32f042单片机中使用正常,自己画的第一版电路板也是f042单片机,刷进去程序后实测功耗低于0.01mA,万用表显示0.00mA。
然而将程序刷进更新后的板子,功耗就上去了,达到了0.88mA,翻了百倍。
好的起先是怀疑硬件电路问题,将外围电路拆除后,功耗竟然上升到1.5mA了。
得,直接找了块新板子只焊了单片机和几个电容,测试还是1.5mA。
这时候基本确定就是程序问题了,当然也有可能是我PCB画的有问题,但是检查了一会儿没发现什么问题,就直接去查程序了。
相关资料
在网络上检索了“stm32f0”“低功耗”“STOP模式”“停止模式”等关键词后,查询到了以下几篇文章,在这里只列出与现在的问题相关的,可能是检索词有问题,最后也只有这几篇文章。
1.https://bbs.21ic.com/icview-329660-1-1.html
2.http://www.stmcu.org.cn/module/forum/thread-613274-1-1.html
3.https://bbs.21ic.com/icview-2533200-1-1.html
5.https://blog.csdn.net/hanping1020/article/details/89431935
前辈说可能是单片机有什么功能没有关掉,所以检索的时候也着重检索了“STOP模式”和“耗电”相关内容。
引用文本
过程
翻了一会儿帖子,基本上都是说IO口配置没有配置好,觉得还是得自己尝试一下。
在单片机开机时,将所有IO口都设置为下拉输入(注意:这里是因为当前PCB只焊了单片机,可以说所有引脚都是悬空状态),然后直接延时五秒钟,然后进入STOP模式,这里要注意一定要延时一会儿,不然接下来在STOP模式是无法下载程序的!
程序下载进去,果然,5秒后进入停止模式,单片机功耗达到0.006mA。
OK!
接下来就是要测试一下什么程序没有关掉。
ADC、USB、定时器、各IO模块晶振应该是全部关掉了,没有检查出什么问题来。
这时候,重点来了,这时候心知肚明的是,一定是有什么东西没有关掉,但是不知道是哪里出的问题。
!直接从初始化入手!
把初始化部分的几个模块逐个注释掉!
果然!注释到USB_Init();时,功耗没有了。
就是USB的锅!
继续检索,这时候检索到写一篇文章,在这里看到了大佬的留言:
USB先复位,再关闭。
检查一下自己的程序,只关闭了,没有复位。
然后抱着试试看的成分在USB关闭之前,写了下面一句话:
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
功耗正常了,就是USB的问题,USB的关闭除了需要关闭以下几个模块之外,需要先将USB复位。
其实在测试过程中还有个小插曲,到了小插曲就基本上锁定了问题所在。因为同一个程序,在F042上ok,在F072上GG。区别是F042使用的20pin,F072使用的48pin,在引脚上除了普通IO口之外,有1个区别:
F042的USB是使用的IO口复用功能,将PA9和10重映射到11和12,11和12这两个引脚拥有USB功能。
总结一下,如果网友们有遇到停止模式或是睡眠模式功耗过高的问题,可以按以下顺序着手测试:
1.先清除PCB上其他元器件,或是只焊单片机,确认GPIO全部悬空。
2.程序初始化阶段,将所有GPIO置下拉输入,延时几秒钟,进入STOP模式或是SLEEP模式,检查功耗是否正常。一般而言,这一步如果正常,那么PCB的问题基本就排除了,当然前提是所有IO都是悬空状态,如果有直接接到VCC或是其他高电平处,该引脚置上拉输入。
3.然后将自己的程序中的初始化部分逐个注释,排查是哪个模块没有关掉。到这一步基本能排查出问题了。
4.根据第3步排查出的问题,检索解决办法。
需要注意的是:要仔细观察功耗的变化,如果程序修改完功耗有变化,那么修改处一定是有问题的。
再总结一下可能出现问题的地方:
1.IO口配置,可先全部下拉,然后检查电路,对需要上拉的地方上拉。悬空脚、接地脚下拉,接VCC或其他高电平信号脚上拉。也可设置输出模式,具体输出当时可以自己测试一下。
2.检查使用到的模块,USB,ADC等都是重点,像USB,要关的话,里面有很多地方都需要关,例如:
CRS_AutomaticCalibrationCmd(DISABLE);
CRS_FrequencyErrorCounterCmd(DISABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CRS, DISABLE);
NVIC_InitStructure.NVIC_IRQChannel = USB_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
NVIC_Init(&NVIC_InitStructure);
NVIC_DisableIRQ(USB_IRQn);
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, DISABLE);
3.注意各模块关闭程序的顺序,例如:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;
GPIO_Init(GPIOF, &GPIO_InitStructure);
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOF, DISABLE);
先设置下拉再关相关IO模块的时钟。对于每个模块,时钟最后关。
-谢谢-