单片机低功耗

出处:http://www.amobbs.com/thread-4932393-1-1.html

 

不知从什么时候开始,随便做个什么电子产品,至少是电池供电的,都要求低功耗
特性了。好在市面上随便什么芯片都敢在自己的数据手册的第一页赫然写着低功耗。究
竟怎样算低功耗?小于5mA?小于1ms?小于100uA?离开了应用场合,似乎数值也失去了
单纯的意义,总之越小越好。但感觉上,能用水果点亮的应用应该就是低功耗了吧。
    认真说来,有点怀念当年随便一个应用500mA,芯片微微发烫,用手一摸只要还能放
得住就大手一挥“没问题”的时代了。最近总是和uA打交道,超过100uA,周围的人脸色
就不好看了,好容易达到了传说中的20uA以内,也会觉得沾沾自喜,哎……uA啊……情
何以堪啊,伤不起啊……
    久病成医,渐渐的也就有了一些心得,似乎低功耗开发的过程也可以一板一眼,按部
就班,似乎不单纯是一些零散的“看情况而定”“只可意会”的东西了。于是忍不住,将
这些似是而非的步骤记录下来,以箪初来者。

 

 

 
事半功倍还是事倍功半——思路决定成败

 



    “肚子饿的时候,睡着了也就不觉得饿了……于是乎,难得的双休日宅在家中补觉,往往也就
一天只吃一餐饭了”——技术宅人_大体如此。
     应该没有人能在梦游的时候干活吧?所以,平常工作的时候,饭还是要吃的。休眠和干活应该
是一对矛盾体。于是乎,芯片数据手册上那些“小的出奇”的休眠功耗,似乎大部分时候只是用来
摆设的;而工作功耗才是实实在在的东西。有时候,为了体现所谓的低功耗,还要在应用中设计一种
所谓的低功耗模式——当系统确认没有事情可做一段时间以后就干脆回家睡觉了——这大体就是现在
市面上常见的低功耗应用的某种程度上的现状吧。于是乎,降低工作频率这种“马儿跑,马儿不吃草”
的逻辑,就成为降低正常工作模式下系统功耗的常规选择。苦啊……多少人在工作频率和功耗间纠结
……又有多少功能实现的本身对对频率拥有最低要求……苦啊——我说的是写代码的程序员。
     
     说起来,降低功耗似乎是一个软件和硬件协同工作才能解决的问题。比如AD采样时候的分压电阻,
如果直接接了地,那么就会一直消耗电流,如果通过一个IO口来控制其接地的方式,只在需要采样的
时候接地,采样完成以后就悬浮或者拉高,就可以将这部分开销降低的最小。
     
     显然,将低功耗完全化作硬件设计的工作或者软件设计的工作都是不合适的。




    >>Figure A
     
     VCC------------------[ R1 ]---+---[ R2 ]--------------GND
                                        |
            _____________     |
                                  |     |
                         AD IO []---+
                                  |
                                  |

    >>Figure B
     
     VCC------------------[ R1 ]---+---[ R2 ]----+
                                   |             |
       _____________     |             |
                              |    |             |
                    AD IO []---+             |
                              |                  |
                  CTRL IO []------------------
                              |




     从硬件角度来说,找到所有可能的消耗电流的回路,一一确定哪些是可以通过软件控制的方式来
优化功耗的,哪些是不可避免的,并给程序的编写人员提供一个所有IO口状态对功耗影响的关系(通
常用简单的表格说明一下高电平会怎样,低电平会怎样,悬浮会怎样就足够了,并不需要精细到具体
的数值。)做到这一点,基本上硬件的工作就告完成,剩下的就是软件开发人员的发挥空间。而基于
软件的功耗降低策略,正是本文所要讨论的重点。

     说到软件功耗优化,说简单也简单,说复杂也复杂。简单总结过来就是:应用模块化、功能任务
化、任务周期化、功耗自理化、休眠一票否决化。还不够简单?再浓缩就是:能休眠就休眠,怎么休眠
投票选。呵呵……估计简单过头了,失去了信息量,下面将这几个方面一一展开:

     1、应用模块化、功能任务化、任务周期化
            一个具体的应用,通常由很多子功能,子任务组成。对嵌入式系统软件构架有所了解的人
        更能理解:一个应用是由对若干服务(servie)的调用实现的。这里服务可以是硬件服务,比
        如AD采样,比如串口通讯,比如外中断触发,比如定时器服务;也可以是软件服务,比如各种
        通讯协议栈,FAT文件系统,队列,软件滤波等等。一个服务通常实现一个或多个功能(好的
        任务划分不会让一个服务包含多于2种以上不相关的功能)。简单的功能,比如CRC校验这样函
        数进去函数出来基本上可以立即获得结果的,我就不说了;复杂的功能最好都使用任务的方式
        来实现。说到任务,就要牵涉到操作系统、调度器或者干脆是简单的状态机了。总之,可以将
        任务的实现理解为一个流程。既然是流程,那么任务所要做的工作就是周期性的。举例来说,
        AD采样任务由至少3个步骤组成:通道选择和启动采样,采样以及等待采样完成,数据的处理。
        这样三个步骤共同组成了一个任务周期,当三个步骤完成以后,我们可以认为一个周期结束了。
        再举一个例子,I2C通讯,一个完整的数据包的发送通常包含了若干的状态,这一系列状态构成
        了一个任务,当最后一个状态(或者某些异常退出状态)结束后,一个任务周期就结束了。
            总结来说, 应用模块化,功能任务化,任务周期化的最终目的就是任务周期化。只有实现了
        周期化,一件事情才有始有终。有始有终,就可以根据需要发放“工资”,避免浪费。而做到
        任务周期化的最常见办法就是通过模块化的服务将功能独立出来从而便于管理,便于找到一件
        事情的开头和结尾。
              找到不拉马的士兵,是功耗管理的起点。而做到这一点,是需要对嵌入式系统拥有全局的
        概念,需要有基于模块化开发,面向服务和接口开发的经验的。经验的积累和全局的概念,是
        最复杂的一个部分。


    2、功耗自理化、休眠一票否决化
            一旦实现了任务周期化,也就等于将整个系统分成了很多周期性工作的小任务,他们可能
        看起来是交错的、并行的或者毫无先后关系的,但从本质上说, 每个小任务只要关心自己的起
        始和中止就好了。系统的功耗管理最后就化简为每个任务的功耗管理——只要每个任务做到了
        功耗最小,那么系统整体在一个有效的协调方式下,就能做到功耗最小。
            根据上面的描述,基于任务的功耗管理实际上就被人为的分成两个部分:微观角度 任务
        自身的功耗管理和宏观角度 多任务休眠的协调。

            我们先从微观来看。一个任务,首先肯定能独立完成自己的功能,这一点看似不起眼,其实
        很关键,他保证了任务中所有的步骤都是确定的,都是“自己说了算的”,对外界来说“都是黑
        盒子”的——简而言之就是“自治”的。在这一基础上,如果要求任务满足低功耗的要求,不外
        乎以下几种情形:
            1)任务执行的过程中,是不允许休眠的,因此任务的开头和结尾处要设置标志——告知协调
       系统,“只要我还没有说OK就不允许休眠”“人在任务在”;
      2)任务执行的过程中,某一些阶段允许休眠,而另外一些步骤是不允许休眠的;如果我们将
              “不允许休眠”看作是休眠的最低等级,那么根据功耗的大小,休眠可以由低到高分为若干
              各等级。这种情况下,我们可以修改上面的定义为:任务的执行过程中,不同阶段允许不同
              的休眠等级。
            3)任务执行的过程中,不在乎是否有休眠。
            
      显然,如果这三类任务同时存在于系统中,第三类任务基本上是“空气”可以无视的,而第一
        种任务是相当霸道的,只要他在执行,就根本不允许休眠;对于第二类任务,即完成了任务,又兼
        顾了休眠,是一个值得表扬的“好同志”。我们在系统任务设计的时候,应该尽可能编写后两类任
    务,而避免或者尝试拆分第一类任务。
      
            从宏观角度来看,任意时刻,可能有多个任务同时在执行,因此每个任务对休眠的需求都是
        不同的。如果要设立一个协调机制,该怎么办呢?难道这个协调机制需要了解每个任务的细节,
        然后“智能”的找到合适的时间点使用合适的等级来休眠么?太繁杂了吧?其实很简单,让每个
        任务都选派一个代表来开会好了——每次这个协调机构想休眠了,就召集所有的代表投票,大家
        每个人提供一个自己觉得能够容忍的最高休眠等级,最后会议的仲裁者从这些投票中找到一个最
        小的休眠等级——也就是水桶的最矮一环作为“会议共识”,然后进入相应的休眠等级。显然,
        如果有人投了“不休眠”得票,仲裁就只能无奈的选择放弃休眠。所以,每一个“任务”都应该
        是一个负责的任务,而不能因为一己私利,为了保证自己任务的执行就草率的选择自己在执行的
        期间“不允许休眠”。正确的做法就是,每个任务都应该根据自己的不同步骤及时的更新自己对
        休眠的容忍度,从而保证开会的时候,能够达成有意义的结果。

            总结来说,如果每一个做事的人都很负责任,任务的划分又很合理,那么通过这种协商机制,
        体统自然就不存在“不拉马的士兵”,也能做到“能休眠时就休眠”了。这种情况下,芯片数据
    手册上那些休眠的功耗数字对你就有了实实在在的意义。怎么样?如果你已经领悟到了,就偷着
    乐吧。如果你还不知道如何具体去实现这些步骤,别着急,随后的章节我们一一为您展开。

 

 

低功耗设计第一步:自底向上,顺藤摸瓜



    
     假想一下,现在有一个新的项目放在你的手上,具体的项目需求包含了AD多通道数据采样,
AD采样后数据的处理(较为复杂),同时还要支持I2C通讯,I2C的通讯协议较为复杂。这样一个
设备必须做到功耗最低。应对这样一个需求,如果已经有一个建议的芯片,比如AVR Mega或者Tiny
我们应该怎么做呢?
 


"先搞清楚我们是怎么睡的"



     第一步,查阅数据手册,找到可被唤醒的最大休眠模式,编写一个测试工程——按照数据手册
所说的要求,实现一个纯粹的什么都不做的休眠模式,同时,关闭所有能关闭的功耗——比如掐断
某些外设的时钟,比如正确设置IO口状态。这样我们就获得了一个极限功耗,也就是正常情况下你
通过系统设计可以无限接近的一个功耗。
     这个时候,你需要的是,根据硬件设计工程师提供的IO口设置建议配置IO状态,以获得一个
子人为的最低功耗。下载代码到目标电路,测量功耗。如果将电路板上无法优化的固有功耗——比
如某些固定消耗电流的电阻功耗——消除以后,仍然没有达到数据手册上所说的对应休眠模式下的
最大值时,你就要找硬件设计的兄弟喝茶了,两个人一起同时从硬件的角度和软件的角度找原因。
直到我们获得一个满意的可自行唤醒的“纯休眠功耗”。
     这个过程非常关键,他直接决定了日后你能达到的最好效果。多花费一点时间是值得的,因为
在这一过程中,你能非常细微的“初步”了解到哪些外设和配置影响功耗,如何影响,有多大的影响。
千里之行始于足下,多花点时间,值!
     切忌,做软件的同学不要一口咬定说问题一定出在硬件设计上。举一个例子:我在这个步骤地
时候,始终达不到数据手册上标注的休眠模式下的最大允许功耗,而根据数据手册,我认为我已经将
所有能关断的外设都关闭了。于是我开始联系IC设计部门抱怨。最后的结果是,有一个外设使用了不
同于CPU的独立时钟——也就是可以理解为异步时钟,在这种情况下,CPU对他的寄存器设置需要一定
的时钟周期才能完成同步。而我在系统中简单的设置寄存器将其“关闭”后立即就去休眠了,可想而
知由于没有等待异步始终同步,也就是这个操作还没有生效,我就去休眠了,这个外设还处于开启状
态,功耗自然居高不下。哎……脸红啊……
 


"再搞清楚我们是怎么醒的"



    第二步,确认系统的脉搏。所谓确认系统的脉搏就是要总体审查整个应用的工作方式,找到一个
系统时钟的最大节拍,并根据这一要求确认芯片所使用的唤醒源。也许很多人都有使用定时器溢出中
断或者比较匹配中断产生一个系统毫秒级时钟的习惯,然而,除使用外部手表晶振的RTC或者异步时
钟源的定时器以外,普通定时器的正常工作都需要系统主时钟提供时钟源,这是我们所追求的低功耗
模式所不允许的。有时候仔细想一想,一个毫秒级别的系统时钟真的是必须的么?
    在AVR中,在低功耗模式下能提供系统时钟的通常就是看门狗了,通过设置,看门狗能够以一个
固定的时间间隔(16ms / 32ms / 64ms / 128ms)将系统从最大的休眠模式下唤醒。因此在那些必须
要用到系统节拍的应用中,如果16ms是你所需系统节拍周期的约数,你就可以考虑采用看门狗来提供
一个并不是那么准确但是非常稳定的时钟源;否则你就要面对以下的选择:
    a. 我的系统工作模式决定了我必须要一个小于16ms的系统时钟;那么整个设计是否允许使用外部
时钟源给异步定时器(Timer2的异步模式)或者某些专门的RTC提供时钟源——这些外设通常支持将系
统从最大的休眠模式下唤醒,就像看门狗做到的那样。
    b. 如果我的系统不允许增加外部时钟源,系统是否允许通过外部触发的模式来工作——也就是
通过外中断或者引脚电平变化中断来唤醒系统,并开始一次工作流程,完成后系统再次陷入永久睡眠。
    c. 如果以上都不行,你可以考虑换芯片或者修改系统的需求的——至少系统需求在功耗的部分
需要做一些妥协。
    
    以上“确认系统脉搏”的步骤实际上是一个“例子”——系统设计的例子,或者说系统工作模式
设计的例子,这是一个系统构架师或者说像我这样“自觉的”系统构架师应该要认真学会并经常实践
的工作。一个笼统而完整的描述如下:
    1) 对一块目标芯片进行调查和确认:确认其所有的休眠模式,以及对应休眠模式关闭的时钟源,
       这些时钟源涉及到的外设——巧妇难为无米之炊,这一步首先搞清楚系统设计的时候手上有
       哪些材料。
    2)研究具体应用的需求,明确系统的工作模式(以采样类的模式来说就是采样,休息,再采样,
       再休息,整个系统是一个状态机并以采样事件作为驱动;采样不仅提供信息,也提供系统的
       脉搏。即便这类系统还涉及到LCD刷新或者I2C/串口通讯,由于信息的本源是采样,因此采样
       周期本身决定了信息的有效性,那么LCD的刷新周期,或者通讯的缓冲跟新周期没有理由必须
       大于采样的更新周期)。在这一前提下,明确系统对唤醒源以及唤醒模式的需求,由此便确定
       了系统的基础休眠模式,进一步说,比较这一基础休眠模式功耗和应用所需的功耗,便可给出
       系统设计的一个初步评估结果。有时候甚至能给出一些系统功耗的直接预期数据。

        举例来说:
       假如通过评估,我们发现“实现应用所涉及到的外设”可以将系统从某个最大允许的SLEEP模式
       唤醒(例如Power-Save Mode),则这个SLEEP模式就是基础Sleep模式,我们评估系统功耗的
       方法就是估算,在完成一次任务的情况下(任务节拍),sleep所占的时间是百分之几,系统
       工作的时间是百分之几(active time),然后用下面的公式就可以估算出系统的正常功耗:

       Equation A:
       normal power-consumption = 
             sleep consumption * sleep time(%) + active consumption * active time(%)

    3)根据研究报告,讨论系统的可行性。如果不可行,则根据已经明确的系统工作模式,对应的唤
       醒源要求重新选择芯片,并返回步骤1)。如果可行,则可以进行后续的设计。

     Figure 1.1 一个能体现低功耗节拍设计的系统状态图

 

单片机低功耗
    
    单片机低功耗

    这种系统设计模式看似有点本末倒置——还没有搞清楚需求就已经把芯片定了——实际上,这种
方式非常符合我们通常的开发模式:先有了一个初步的概念或者备选芯片方案,这些方案可能来自一个
已有的方案,一个已有方案的兼容方案,一个老板或者老员工/经验者提出的方案——总之有了一个基
础或者说原形,我们开始调查和研究具体低功耗的可行性,并形成了一个研究报告,这一报告将直接
指导下一步的行为:由于需求非常明确,我们可以决定是否更换芯片或者直接进入下一步的开发。上
面三个步骤实际上形成了一个LOOP,这一loop其实来自于“快速原型法”这一古老的“敏捷”开发模式
自然,规范,高效。

  完成了以上两个步骤,可以说这一阶段就结束了,至此我们对系统的关键性能数据已经成竹在胸:
系统最低能实现多大的功耗;外设某些敏感的参数设置将如何影响功耗——当我们需要在外设性能和
功耗之间做妥协和权衡的时候这些信息就将发挥巨大的作用;我们甚至对系统外来如何工作,或者说
系统最基本的问题:“时间问题,整个复杂的多米诺骨牌是从哪里被什么推倒第一张牌的”大致有了
了解。我们甚至知道,如果不出意外系统将会达到怎样的功耗。
  简单说,我们已经知道系统是能够实现的,功耗会在什么范围也是大体有所概念的。万事俱备,
只欠东风。欲知后事,请听下回分解。
    


本小结的一个附录:试探功耗底限的系统配置方式——分享一些实实在在的经验



     A. 对AVR来说,不用的引脚怎么办?
        >> 如果这个引脚属于ADC采样引脚
            i) 通过DIDRn寄存器关闭对应引脚的数字输入,这个时候PINX对应位将永远读取到0
            ii)通过DDRx和PORTx寄存器将对应的引脚设置为输入,“关闭”上拉电阻
        >> 如果这个引脚是普通的GPIO
            官方推荐的方式是给这个引脚一个确定的电平,比如:
            i) 通过DDRx和PORTx寄存器将对应的引脚设置为输入状态,并“开启”上拉电阻
            ii)通过DDRx和PORTx寄存器将对应的引脚设置为输出状态,并输出低电平,PCB设计上,
               将该引脚接地。
        >> 如果这个引脚是RESET引脚
            当电路要求保证稳定的情况下尽可能简化,同时,VCC电压在上电时刻电压升高速度不会很缓慢,
            则接外部上拉电阻到VCC,这样虽然对功耗影响不大,但是可以适当提高一点抗干扰性。
        >> 如果这个引脚是扩展的ADC引脚
            基本可以不管,或者接地。

     B. 对AVR来说,需要使用的引脚怎么办?
        >> 如果这个引脚是开漏输出/线与输入的引脚,比如TWI,同时需要与外部设备连接,而这一连接是允许
           拔插的
           i) 如果逻辑上允许,接下拉电阻。
           ii)如果是外中断引脚或者因脚电平变化中断引脚,避免悬浮,相比上拉来说,尽可能选择
              下拉。这样设置的目的是避免不确定电平经常将系统唤醒。选择下拉的原因是将高电平
              的选择权力交给外部设备,同时更倾向于盗电(*^_^*)。
        >> 对于ADC引脚
           i) 如果永远不会用于数字信号的输入用途,请参考空闲引脚的处理方式。
           ii)如果需要用作数字信号的输入用途,请在通过PINx读取电平前,通过DIDRn寄存器打开
              对应引脚的数字输入,并插入两个NOP后读取电平,完成读取后,立即关闭数字输入功
              能。
        >> 对于控制信号引脚
           i) 直接驱动LED总是悲剧的开始,别忘记加入限流电阻,尽可能使用高亮LED。
           ii)如果非要输出电平的控制信号,请认真考量有没有漏出电流的可能,如果有,请尽可能
              在不需要输出控制信号的情况下,将IO口处理为无电流漏出的状态(或最小小电流漏出
              的状态,关于出还是入的语言文字问题,你懂的),具体状态图应该由硬件设计人员给
              建议。总原则就是按需分配。

     C. 说说PRR寄存器
        >> 如果某个外设的供电通过PRR寄存器的设置被掐断了
           i) 除非特殊说明,否则这个外设的所有寄存器都是无法正确读写的
           ii)如果在外设供电关闭前,外设的中断标志没有被清零;或者说正在执行这个中断处理程
              序的时候该外设被断电了,则中断标志不会被清除。表现症状就是中断持续被触发。其
              实想想很简单,参考i)就知道了。
           iii) 很多时候,关闭定时器这样的外设并不能减少多少功耗,基本上都是小于5uA的。经验
              上关闭那些和模拟特性相关度较大,或者拥有独立相关的时钟源的模块,通常会减少不小
              的功耗。
           iv) 谨慎使用该功能,除非你认真阅读了数据手册。这也是很多人所谓休眠醒不过来或者工
              作不正常的主要原因之一。

     D. 说说工作频率         
        >> 在正常的工作模式下,频率越高功耗越高。
            i) 推论1:对于同样一个工作,频率越高,完成该工作的时间越短
            ii)推论2:根据Equation A,对于同样一个工作,Active的时间越短,则Sleep的时间越长。
        >> 假设频率翻倍,功耗增加4倍,则:
            i) 推论3:通常Sleep功耗至少为某一个频率功耗的4分之一甚至更大。当频率翻倍的时候,
               工作时间缩短一半,假设功率翻倍时功耗为4倍,则Active部分的实际功率翻倍
               (50% * 4);同时,节省出来的时间成为Sleep功耗,此时,系统的功耗变化为:
               
               假设频率翻倍前的Active功耗认作 C,工作时间为T,则:
               翻倍前Active部分的功耗为  C * T
               频率翻倍后,Active的功耗为 4C,工作时间为 T/2;同时,假设Sleep的功耗为 C/4,则
               翻倍后的实际功耗为
               4C * (T/2) + (C/4) * (T/2) = 4.25C * T / 2 = 2.125 (C * T) 
               可见频率翻倍后实际功率为增加前的2.125倍。显然从功耗的角度来说并不划算。

               但请注意,Sleep功耗通常远远小于这里的1/4,以ATmega88为例,1MHz VCC = 2V的情况下
               最大功耗是550uA,而Sleep模式(Power-down VCC=3V)最大功耗是15uA,差不多36倍。在
               这种情况下,显然频率翻倍,功耗接近2倍。
               
               有意思的是,如果对以上公式进行迭代,你会发现,频率越翻倍,Sleep功耗和翻倍前的
               Active功耗差距越大。也就是说基本上每次翻倍,功耗基本上可以认为是翻倍的。同时
               频率增高带来的好处却是运算速度每次都翻倍的。从这个角度来说,是否频率越高越好呢?
               (速度快,功耗增加小)。再联系到那些与外部引脚操作直接相关的功耗,频率越高,外部
               引脚操作中可控的功耗部分就小(请联系前面AD的例子),那么从这个角度来说,似乎功耗
               还会减小一些。

               再次强调,以上结论建立在工作完成后立即休眠的工作模式下,同时Sleep模式的功耗必须
               远远小于Active功耗(通常8~10倍),使用外部时钟源,以及晶体振荡器所需的额外功耗,
               及从休眠中唤醒时时钟稳定期间所需功耗都未作考虑。
         >> 实际上,MCU的功耗分为两个部分,一个与频率有关,一个与工作电压有关,即
               E = E(V) + E(f)
               当频率翻倍时,影响的只是E(f),而这部分功耗并不会最终导致4倍的功耗,其值往往在2倍
               甚至更低。在这种情况下,Sleep+Active的工作模式会带来更低的功耗。证明略。
            
        >> 通常,我们测量功耗的方式就是测量电流
            i) 推论4:在非积分式功耗测定方式中,如果工作频率越高,则Sleep时间越长,在电流测量的
               时候,Active电流越接近于“毛刺”,这就导致了频率越高,功耗越低的假象。因为大部分的
               电流采样点都落在了Sleep上。
            ii)推论5:采用积分式功耗测定方法才能正确的测定实际功耗。当然,如果你想骗骗普通客户,
               高精度电流表的电流结果(甚至是平均电流)都将反馈给你一个“非常理想的结果”。

 

 

低功耗设计第二步:让我们来下棋,很大很大的一盘棋



        通过上一节的讨论,假设在您的设计中对应的步骤已经完成,则我们至少获得了以下信息和结果:
    1. 一个极限功耗
    2. 一个可行的系统工作模式(满足应用需求同时兼顾低功耗的系统节拍)
    3. 当使用2中提及的系统工作模式时,通过公式计算获得的理论系统功耗(系统正常工作下的功耗)
    
        显然,万事俱备,只欠东风,就只剩下具体实现了。别着急,我们先来搞清楚几个定义。

    a. 普通工作模式(Normal Mode / Active Mode)
        这里的普通工作模式是指能够实现正常系统功能的模式,在这种模式下,MCU并非一直处于工作状态,
    而是根据前面一章提到的功耗公式,结合了Active和Sleep两种MCU状态的模式。简而言之,一个保证了应用
    基本功能的同时能休眠就休眠的工作模式。
    b. 低功耗模式(Idle Mode / Sleep Mode)
         这里所说的低功耗模式是指根据用户的应用需求,在用户指定或者系统自动侦测满足某些特定条件的
    情况下,尽可能关闭不需要的功能,仅保留某些应用必须的任务以降低功耗为目的的模式。(例如一段时间
    没有用户操作就关闭LCD和LED背光)
         
        总结来说,这里的普通工作模式和低功耗模式都不直接对应MCU提供的Active和Sleep模式,而是两个
    根据用户功能需求定义的具有不同功能配置的功耗模式。他们可能都牵涉到MCU的Active和Sleep状态。明确
    了这两个定义,我们后续讨论中牵涉到的很多说法才不会混淆。
    
    2.1 工欲善其事,必先利其器
        在实践低功耗系统设计前,我们必须要有一个有效的手段来检测或者说观察系统当前的工作模式,通俗
    的说就是要能够随时知道系统什么时候工作,什么时候休眠,并且最好能够准确的知晓工作和休眠的时间比
    例。对于缺乏高精度电流表的场合来说,这种观测手段就更为重要了。
        简而言之,我们需要一种实时追踪(trace)系统功耗模式的调试(Debug)手段。既然是实时追踪,意
    味着断点、单步这种常见的手段是不行的,系统必须保证处于正常的非间断工作状态下。同时,作为Debug,
    必须能够准确显示休眠和工作的状态,并能够将这些信息保存下来,大家可以在脑海里想像有这么一个类似
    地震记录仪的设备,一直不停的在纸带上记录着功耗变化的信息。
        说的这么复杂,其实做起来很简单。Debug阶段,我们关系的是系统如何休眠的,其实际功耗可能由于
    Debug手段的存在而并不准确,但这一信息已经足够了,因为在随后的检测中,我们可以生成一个release版
    本(移除了debug相关的代码)直接通过电流表检验系统功耗。Code 2.1就是一个很好的例子。代码在休眠前
    在某一个信号引脚上输出高电平,在退出休眠模式后输出低电平。此时,借助示波器或者逻辑分析仪的帮助,
    我们就可以记录并检测系统的功耗模式,甚至根据数据手册提供的Active电流和Sleep电流计算出一个非常
    接近实际结果的理论_功耗。
 


Code 2.1 一个Tiny下进入Sleep模式的代码例子

  1.  
  2. static void enter_sleep_mode(uint8_t chLevel) 
  3. {
  4.     /*! \brief sleep mode select bits
  5.      *!        MODE                 SM2  SM1 SM0
  6.      *!        idle                 0    0   0
  7.      *!        ADC Noise Reduction  0    0   1
  8.      *!        Power-save           0    1   1
  9.      *!        Power-off            1    0   0
  10.      */
  11.     static FLASH uint8_t c_chSleepLevel[] = {
  12.                             ((0x00 << SM0) | _BV(SE)), 
  13.                             ((0x01 << SM0) | _BV(SE)),
  14.                             ((0x02 << SM0) | _BV(SE)),
  15.                             ((0x03 << SM0) | _BV(SE)) };
  16.     uint8_t chSleepMode = c_chSleepLevel[chLevel] /* | _BV(SE)*/;
  17.     
  18.     SAFE_ATOM_CODE(
  19.         MCUCR = (MCUCR & ~(_BV(SM0) | _BV(SM1) | _BV(SE))) | chSleepMode;
  20.         ENABLE_GLOBAL_INTERRUPT();      //! enable interrupt
  21.  
  22.  
  23.         set_signal_a();    //! 即将进入sleep前将信号引脚置高
  24.  
  25.  
  26.         __sleep();                      //! sleep
  27.         //!< clear sleep control register
  28.         MCUCR &= ~(_BV(SM0) | _BV(SM1) | _BV(SE)); 
  29.  
  30.  
  31.         clear_signal_a();   //!< 退出sleep模式后将信号引脚拉低       
  32.  
  33.     )   
  34. }

复制代码



        有了这样一个手段,我们就能很方便的进行实时调试,设计出“能休眠就休眠”的好算法。这也是我们
    后续讨论的基础。

    Figure 2.1 一个可能的系统功耗模式监测的样例
     单片机低功耗

    TO BE CONTINUE...

 

 

以前网上找的:
现在,有许多单片机应用领域,都是用电池供电,节能成为设计工程师普遍关心的问题。希
望大家就这方面展开讨论。
    
    以下提供一些讨论的方向:
    
    1、如何降低系统功耗?(软件?硬件?)
    2、各位在这方面有何经验教训?(可以拿出来与大家分享)
    3、各种芯片的功耗比较?
    4、SLEEP模式应用的注意事项?
    5、一些新型的节能器件的介绍?
    6、其它与低功耗设计相关的话题?……
    
进入掉电模式
现在有很多的低功耗的片子,特别是在进入掉电模式之后,只有1uA的电流。也可以使用电源管理
的方法,在不工作的时候,把系统电源关断,这样更省电

我用了很久51芯片,本来对它的功耗非常不满,但是因为其价格越来越便宜,本身的性价比依旧
很好,所以总也甩不掉。

1、休眠。一般的系统都不会到了忙不过来的地步,适当的休眠还是可以节省一些功耗的,在一些
简单的系统,多抽时间休眠成了省电的关键,你看别的芯片都不耗电,只有单片机了,它就是关
键了,在有些时候,提高主频反而会获取更多的休眠时间,反而使系统功耗更小了。但是值得注
意的是,经常性的切换休眠和工作状态会让电源产生mV级的波动,特别对于很多线性稳压器只有
100mA以内的输出能力的情况更明显,这样的波动或许会影响系统内的AD和一些其他模拟电路,
值得注意。

2、掉电。如果进入了掉电模式,很多51芯片是无法通过中断重新开始工作的,可以外加一个微功
耗的单片机来提供复位,这个单片机只负责键盘扫描和复位51单片机,以及发送键盘编码到51芯
片。 我以前见过一个手持设备,耗电很小,但是包括了大容量存储、显示、输入、数据输出、检
索等功能,平时89C51总是处于掉电状态,但是有了键盘操作后,就复位开始运行,处理完键盘送
来的任务之后又自动掉电了。

3、复杂运算。复杂运算(譬如指数运算、浮点乘除)一定会占据更多系统时序,响应减少休眠时
间,可以通过查表方式,这样用大容量的表格代替了现场计算,更多的时间不就可以睡觉了吗?

4、如果软件任务少到一定程度,那么可以考虑把晶体搞到32k去运行,其实这样更省电,但是这
意味着51软件基本没什么高速的事情做,也不需要串行通信,否则,还是老老实实面对现实吧。

我觉得,51芯片用于电池供电的系统不是很合适,但是从开发周期看,它的开发环境很好,毕竟
可以承载8位机的相对大型的应用,有时候又不得不用它。我觉得距离51最靠近的AVR单片机更适
合将来的应用,因为其性能价格比相对其他单片机还是不错的,除非51芯片可以将来做到在3MIP
下,工作电流小于2mA,休眠电流小于500uA,掉电电流小于10uA。
在很多的设计中,采用线性降压的方法,电源损耗大,如提高供电电压,并用高效率的DC-DC电
源,可延长电源使用的时间
89C8252掉电工作,看门狗做“系统运行时钟”同时把看门狗复位“软件模拟成看门狗中断”
“狗”叫一次跳起来看看,“RAM值班室登个记”,同时还登记下当前PC+1的值,然后“睡死”
过去!
平均功耗不大于5V/0。3MA,而且有很强的抗干扰性!
软件优化很重要!
如64MS一次“狗”叫!起来做40条指令,24MHZ下最多:40*0。5=20US
于是占空比:20/64000=1/3200    即平均电流下降3200倍!!!
外设会受复位改变吗?当然!但锁存器干什么啊?!
如何知道程序能运行多久?下一条运行指令运行到那?
如果任何时刻,你自己编的程序运行在那个片区,你都不知道,那还叫什么搞软硬件的要天人合
一啊?!
系统任务不忙的情况下,你的看门狗定时复位方法还可以,但是。。。好多情况下似乎做不到呀

    
我的51系统只有200微安
省电是个大难题,特别是51,但只有用心还是可以做到的,特别是工作任务少的时候。我的一个
水文遥测系统,用12伏电池供电耗电只有200微安,有8Mbit data flash,一个调制解调器,一
个时钟,一个485通信口,一个232通信口,还有6个数码管,是不是够多的了,但它们平时都不
工作,我也是用看门狗复位来唤醒51单片机的,每1.6秒一次,用的是x25045,可是25045的复位
时间有200毫秒之多,实验发现,51从掉电返回到正常工作只要有30个毫秒足了,别小看节省的
这一百多毫秒,因为51在每次醒来是只要发现没有任务就可以马上POWERDOWN了,所以加了一个
CMOS的单稳来复位。其它的就是口线的状态一定要注意,不要让它吸收电流也不要输出电流,要
是做不到可以试着加一此电路,如反相器.

稳压电源是个要权衡的事,虽然开关稳压有较高的效率,但在低功耗设计不一定对,开关电源本
身消耗的电流就是一个大问题,一个微安级的系统也许要特别对待,我用的是max667线性稳压数
微安静态电流.我想开关电源做不到
对于外部事务频繁的应用,无法使用掉电方式
虽然很多51芯片支持外中断触发芯片脱离POWER DOWN状态(如华邦的W78E58、W77E58),但还
是解决不了串行通信的问题,而且对于需要内部精确定时的场合,从POWER DOWN到正常工作需要
很长时间,这个恐怕还是难于让人接受。莫非没有一个厂家可以产出高速小功耗的51芯片?没到
理呀,PHILIPS不是玩了很久吗?怎么弄出的芯片在12MHz下还是大于10mA,休眠也有几个mA,这
也吹牛没下功夫嘛!

用51做低功耗,太累了
低功耗多得是,象PIC、EMC轻松做到20uA以下,51有POWER DOWN,但只能复位唤醒,有少数可
用INT唤醒,太麻烦。有些有双晶体的单片机,做低功耗最简单,平时用32768工作也只有20uA,
这种单片机一般带有LCD。EMC内有PLL单片机做功耗系统很方便,象78565,567,功能强价格低

samgsung的单片机可以做到
565匠人也用过。平时进IDLE模式,功耗只有几个UA
分级供电和外部唤醒确是一种可行的办法
   在分级供电中要注意的是如果电源是小电流的稳压器件最好有一个比较大的蓄电电路,要不然
单片机唤醒和上电时可能会起动不了,而且可能会进入一个不希望的振荡期,比如单片机要起
振,电流增大,这时电源供不起,电压就下降,引起的是单片机又停振电压又回升!所以一个合
理的电源管理电路就显得很关键,这方面的专业IC将是未来一个很有前途的产业!这个IC应有一
个内部低速的定时器和一个专门的蓄电管理电路,当电路进入低功耗后应该将蓄电电路冲满以备
唤醒和大功耗时用,这种电路主要用于小电流供电的环境,它可以为小电流供电环境提供一个短
时间的大电流工作。    另外单片机的耗电除了核本身的耗电外,大多是IO口的耗电,大家可以
通过降低主频,将IO口置在比较合适的状态来达到一个比较省心又省力的方式。而且不全理的频
繁唤醒有时会带来更多的电耗!    

用TI的单片机MSP430系列非常省电。正常工作时几百微安,掉电时约1微安
87LPC76X低功耗51,32k时20uA
使用双振的单片机,在系统不忙的时候使用32768的晶振,同时进入SLEEP这样处理通常耗电都在
几个uA.在处理SLEEP唤醒后的程序需要小心处理,特别是*的单片机,有时厂家给出的资料都
要小心,我碰到过。
我不知道您是用的哪家的51单片机,功耗能做到这么低。据我所知ATMEL89C52 Powerdown mode
下最少是40微安。您的系统中有这么多的器件,即使都是低功耗可关断的器件,那你的系统每次
工作时都要启动所有的器件才能运转起来,这个启动过程是多长呢?还有您的单片机不会工作在
12V的,你还需要一个电压变换器,它平时不用电的吗?你的CMOS单稳不用电的吗?据我所知常
用的485,232,modem,flash都不是低功耗可关断的,如果您都使用的是特殊器件,那实用的意
义何在呢?或者您使用了其他器件来控制这些耗电多的设备,那您一定是硬件高手了。可否指点
一二?
高速51: C8051FXXX在1M指令流下,VDD仅仅1.5mA
用IO口控制RC振荡频率?
用RC振荡方式,并将IOSI口接一个电阻到IO口上。通过切换IO口的电平来切换频率,方法如
下:            功耗,在电池供电的仪器仪表中是一个重要的考虑因素。PIC16C××系列单片
机本身的功耗较低(在5V,4MHz振荡频率时工作电流小于2mA)。为进一步降低功耗,在保证满
足工作要求的前提下,可采用降低工作频率的方法,工作频率的下降可大大降低功耗(如PIC16C
××在3V,32kHz下工作,其电流可减小到15μA),但较低的工作频率可能导致部分子程序(如
数学计算)需占用较多的时间。在这种情况下,当单片机的振荡方式采用RC电路形式时,可以采
用中途提高工作频率的办法来解决。                             具体做法是在闲置的一个
I/O脚(如RB1)和OSC1管脚之间跨接一电阻(R1),如图1所示。低速状态置RB1=0。需进行快速
运算时先置RB1=1,由于充电时,电容电压上升得快,工作频率增高,运算时间减少,运算结束又
置RB1=0,进入低速、低功耗状态。工作频率的变化量依R1的阻值而定(注意R1不能选得太小,
以防振荡电路不起振,一般选取大于5kΩ)。

改用C8051Fxxx,20MHz 仅仅10mA,若降到1MHz,可以做到1~2mA;
2. 或是干脆采用MSP430,一般<1mA,稍稍采取措施,马上可以接近零功耗!

   大家不要以为更换CPU是很难的事情,我们仅仅用2周就更换成功CPU
先天不足,51低功耗没前途的
msp430,m16等有很多低功耗单片机,功能强,又是精简指令,全天uA级工作
成本也是关键,不一定非要低功耗器件。
我觉得要很好的利用单片机的中断和休眠功能,单片机尽可能的处于休眠等待状态,同时注意空
闲IO口的状态,输出的最好置低,输入的要视外围电路而定,不用的脚要处理好,不是简单不接
就可以的
另外,外围电路可以做分区域的电源开关,不用时,关闭电源,并将与其相连的单片机的IO口置
低,减少信号线馈电。
不知说的对不对。
    刚开始做电池产品时,只有8031 ,考虑用PSEN什么的控制外部RAM,休眠方式,但是还是在十毫
安级.    现在好了,有许多型号单片机本身就是低功耗,为了减少体积,还要追求更低.   1.系统
设计,好的系统设计是降低功耗的关键.   减少外围器件,降低晶体频率.可以采用带lcd,ad,实时
时钟功能的单片机,即降低成本,又减少了故障率,可谓一举两得.HOLTEL,PHILIPS,PIC 都有此类
单片机.   低的主频也可以降低功耗,如ZILOG的单片机可以程序控制对主频的分频,在不忙时把
频率降低,需要时在提高. HOLTEK的可以采用双频率工作,高主频可以关闭,32768可以提供内部精
确计时,还可以**休眠的单片机工作.    2.降低系统电压,可以降低功耗.    3.合理处理不用
的IO口,最好设为输入态.对外围电路也要考虑,如光耦,尽量使其导通态<断开态.驱动三极管的状
态.还有就是上拉,下拉电阻值,太小也会造成漏电.

Mega8的一个特点是带有内部的RC振荡器,别小看他,他与晶振的不同之处在于他的起振时间很
短,只要几uS,而晶振一般要几十mS,所以低功耗设计时一定要用,430的宣传不是也讲起动时
间6uS吗,那一样是指的RC振荡开始工作的时间。
我得设计静态电流50uA,实际只是LCD模块的电流,单片机平时处在掉电的状态。每隔1S倍液晶
模块唤醒一次,作一次显示的刷新工作,耗时约4mS,正常工作时如果有脉冲来的话,就作一些运
算,脉冲频率50Hz,每次运算不过200uS,这样下来,正极的功耗大大降低,加上一些外围电
路,平均在100uA以下。

低功耗设计

现象一:我们这系统是220V供电,就不用在乎功耗问题了
点评:低功耗设计并不仅仅是为了省电,更多的好处在于降低了电源模块及散热系统的成
本、由于电流的减小也减少了电磁辐射和热噪声的干扰。随着设备温度的降低,器件寿命则
相应延长(半导体器件的工作温度每提高10度,寿命则缩短一半)

现象二:这些总线信号都用电阻拉一下,感觉放心些
点评:信号需要上下拉的原因很多,但也不是个个都要拉。上下拉电阻拉一个单纯的输入信
号,电流也就几十微安以下,但拉一个被驱动了的信号,其电流将达毫安级,现在的系统常
常是地址数据各32位,可能还有244/245隔离后的总线及其它信号,都上拉的话,几瓦的功
耗就耗在这些电阻上了(不要用8毛钱一度电的观念来对待这几瓦的功耗)。

现象三:CPU和FPGA的这些不用的I/O口怎么处理呢?先让它空着吧,以后再说
点评:不用的I/O口如果悬空的话,受外界的一点点干扰就可能成为反复振荡的输入信号
了,而MOS器件的功耗基本取决于门电路的翻转次数。如果把它上拉的话,每个引脚也会有
微安级的电流,所以最好的办法是设成输出(当然外面不能接其它有驱动的信号)

现象四:这款FPGA还剩这么多门用不完,可尽情发挥吧
点评:FGPA的功耗与被使用的触发器数量及其翻转次数成正比,所以同一型号的FPGA在不同
电路不同时刻的功耗可能相差100倍。尽量减少高速翻转的触发器数量是降低FPGA功耗的根
本方法。

现象五:这些小芯片的功耗都很低,不用考虑
点评:对于内部不太复杂的芯片功耗是很难确定的,它主要由引脚上的电流确定,一个
ABT16244,没有负载的话耗电大概不到1毫安,但它的指标是每个脚可驱动60毫安的负载
(如匹配几十欧姆的电阻),即满负荷的功耗最大可达60*16=960mA,当然只是电源电流这
么大,热量都落到负载身上了。

现象六:存储器有这么多控制信号,我这块板子只需要用OE和WE信号就可以了,片选就接地
吧,这样读操作时数据出来得快多了。
点评:大部分存储器的功耗在片选有效时(不论OE和WE如何)将比片选无效时大100倍以
上,所以应尽可能使用CS来控制芯片,并且在满足其它要求的情况下尽可能缩短片选脉冲的
宽度。

现象七:这些信号怎么都有过冲啊?只要匹配得好,就可消除了
点评:除了少数特定信号外(如100BASE-T、CML),都是有过冲的,只要不是很大,并不一
定都需要匹配,即使匹配也并非要匹配得最好。象TTL的输出阻抗不到50欧姆,有的甚至20
欧姆,如果也用这么大的匹配电阻的话,那电流就非常大了,功耗是无法接受的,另外信号
幅度也将小得不能用,再说一般信号在输出高电平和输出低电平时的输出阻抗并不相同,也
没办法做到完全匹配。所以对TTL、LVDS、422等信号的匹配只要做到过冲可以接受即可。

现象八:降低功耗都是硬件人员的事,与软件没关系
点评:硬件只是搭个舞台,唱戏的却是软件,总线上几乎每一个芯片的访问、每一个信号的
翻转差不多都由软件控制的,如果软件能减少外存的访问次数(多使用寄存器变量、多使用
内部CACHE等)、及时响应中断(中断往往是低电平有效并带有上拉电阻)及其它争对具体
单板的特定措施都将对降低功耗作出很大的贡献。