armok 发表于 2008-6-26 13:44:45

【阿莫AVR芯片检测系列文章5】电源管理(工作电流、休眠电流、休眠进入与唤醒)测试器

这是我为邮购部的AVR拆机件而制作的测试器。

按一下切换开关,切换到200uA电流档(最小能显示0.1uA),显示休眠电流。(本想设计成自动切换电流表的,详情请参考2楼)

本资料包括:

   1. 功能描述
   2. 实物图
   3. 电路图
   4. AVR源代码(GCC)
   5. 适合生产检测用的DOS批处理



http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327202.jpg
(原文件名:休眠工作电流(6.3uA).jpg)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327203.jpg
(原文件名:正常工作电流(12.3mA).jpg)



功能描述

本检测器的经验数据:

器件:ATmega16-8AI/8AU/16AI/16AU
熔丝位设置: D9D4 (高低位),即8M内部RC频率,JTAG取消
工作电流参考值: 12.0-13.2 mA (大量拆机芯片实测结果)
休眠工作电流参考值: 3-8uA (大量拆机芯片实测结果)

软件下载到AVR芯片后开始执行,200mA的数字表头(最小能显示0.1mA)显示当前的工作电流。工作灯不停闪烁约2秒钟后,自动进入休眠状态。
休眠后按INT0,INT1或INT2按钮,能唤醒休眠状态,返回正常工作模式。工作灯不停闪烁约2秒钟后,自动进入休眠状态.....

按一下切换开关,切换到200uA电流档(最小能显示0.1uA),显示休眠电流。(本想设计成自动切换电流表的,详情请参考2楼)

为获得更准确的检测数据,避免干扰,需要将所有IO口设置成以下之一:

1。输入,带上拉电阻。
2。输出0
3。输出1
如果是输入不带上拉电阻,静态工作电流是跳动的,并且容易受干扰。所以,将JTAG的熔丝位也取消。

注意:

1. 为了准确显示AVR的工作电流,LED使用了一只三极管驱动,三极管的CE极电流不纳入数字电流表的统计数值内。
2. 200uA的数字电流表可以承受较高的电流,所以,不小心误按了切换开关,也不会损坏电流表,只会显示超量程符号。
3. 200mA的电流表的内阻是1欧。200uA的内阻是1K。




DOS批处理(适合生产用):

@echo off
rem Atmega-16的ID是0x-1e 0x-94 0x-03.ATemga-32的ID是0x-1e 0x-95 0x-02。缺省熔丝位均是-f0x99e1。
rem 测试IO扫描时的熔丝位均是:-f0xd9d4
rem 改成ATmega-32时,需要做以下的替换:
rem ATmega.16 -> ATmega.32
rem 0x.94   -> 0x.95
rem 0x.03   -> 0x.02
rem 16K       -> 32K
rem M.16      -> M.32


@echo ****************** 本软件由阿莫编写 2008.06.17 ************

:start
@echo 请放入新的芯片(ATmega16 0x1e 0x94 0x03),即将进行第③个检查。
@echo 本检查包括:Power Manager电源管理,INT外部中断 (ISP下载)
pause

@echo ---- 检查芯片的ID是否正确 ---
STK500 -dATmega16 -s -cCOM4 |findstr/i "0x1e.0x94.0x03" & if errorlevel 1 (goto error_s)


@echo ---- 设置成8M的工作频率 ---
STK500 -dATmega16 -cCOM4 -f0xd9d4 |findstr/i "failed" && goto error_f


@echo ---- 擦除芯片 ---
STK500 -dATmega16 -cCOM4 -e | findstr/i "failed" && goto error_e

@echo ---- 写入ADC程序并校验 ---
STK500 -dATmega16 -cCOM4 -ifD:\AVR_test\M-16_M-32\default\power_manager.hex -vf -pf | findstr/i "failed" && goto error_if


@echo -----------------------------------------------------------------
@echo 绿灯亮时左边电流约12.0-13.2mA。大于15不正常
@echo 灯不亮时按右边开关显示约3-8A。大于10不正常
@echo INT0,INT1,INT2依次按测试中断唤醒休眠状态
@echo -----------------------------------------------------------------
goto start


:error_s
@echo ***********************************************************
@echo ***********************************************************
@echo *** 警告!!不正确的ATmega16 ID (Signature) 芯片不合格***
@echo *** 只有右边的显示数字是0.00时,此操作才能成功          ***
@echo ***********************************************************
goto start

:error_f
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!设置8M频率有错误,芯片不合格!         *******
@echo ***********************************************************
goto start

:error_I
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!设置ISP 921.6KHz速度有错误,芯片不合格!****
@echo ***********************************************************
goto start

:error_e
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!擦除芯片有错误,芯片不合格!            ****
@echo ***********************************************************
goto start

:error_if
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!FLASH写入校验有错误,芯片不合格!      ****
@echo ***********************************************************
goto start

:error_ie
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!eeprom 写入校验有错误,芯片不合格!      ****
@echo ***********************************************************
goto start

:error_I_2
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!设置ISP 230.4KHz速度有错误,芯片不合格!****
@echo ***********************************************************
goto start





电路图:

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327082.jpg
(MCU部分)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327083.jpg
(ISP接口)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327084.jpg
(供电)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327088.jpg
(电流表与切换线路)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327086.jpg
(显示LED及驱动线路)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_327087.jpg
(复位与外部中断按钮)



源代码:

/***********************************************
****      AVR电源管理_睡眠模式范例         ***
****                                           ***
**** armok 改编自 HJJourAVR的范例             ***
**** 编译器:WINAVR20050214                   ***
****                                       ***
****www.OurAVR.com       2008.06.26         ***
***********************************************/
/*
本程序简单的示范了如何令AVR ATMEGA16进入睡眠状态及唤醒
                电源管理及睡眠模式的介绍
                进入最低耗电的掉电模式
                关闭各种模块
                外部中断唤醒

M16掉电模式的耗电情况(看门狗关闭),时钟为内部RC 1MHz
   0.9uA@Vcc=5.0V[手册的图表约为1.1uA]
   0.3uA@Vcc=3.3V[手册的图表约为0.4uA]
   //测量的数字万用表是FLUKE 15B,分辨率0.1uA

这个程序需要MCU进入休眠状态,为实现最低功耗,JTAG接口会被关闭,只能通过LED的变化来观察程序的运行。
这个实验里面,用STK500(AVRISP) ISP下载线来烧录更方便。

熔丝位设置
1 关断BOD功能 BODEN=1
2 如果用ISP方式烧录,就可以完全关闭JTAG口了OCEEN=1,JTAGEN=1

*/

#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
//时钟定为内部RC 1MHz,F_CPU=1000000 也可以采用其他时钟
#include <avr/sleep.h>
/*
sleep.h里面定义的常数,对应各种睡眠模式
#define SLEEP_MODE_IDLE         0
空闲模式
#define SLEEP_MODE_ADC          _BV(SM0)
ADC 噪声抑制模式
#define SLEEP_MODE_PWR_DOWN   _BV(SM1)
掉电模式
#define SLEEP_MODE_PWR_SAVE   (_BV(SM0) | _BV(SM1))
省电模式
#define SLEEP_MODE_STANDBY      (_BV(SM1) | _BV(SM2))
Standby 模式
#define SLEEP_MODE_EXT_STANDBY(_BV(SM0) | _BV(SM1) | _BV(SM2))
扩展Standby模式

函数
void set_sleep_mode (uint8_t mode);
设定睡眠模式
void sleep_mode (void);
进入睡眠状态
*/

//管脚定义
#define LED                        0   //PB0 驱动LED,低电平有效
#define KEY_INT0        0   //按键,   低电平有效
#define KEY_INT1        0   //按键,   低电平有效
#define KEY_INT2        0   //按键,   低电平有效

void delay_10ms(unsigned int t)
{
/*
        由于内部函数_delay_ms() 最高延时较短
        262.144mS@1MHz / 32.768ms@8MHz / 16.384ms@16MHz
        故编写了这条函数,实现更长的延时,并能令程序能适应各种时钟频率
*/
        while(t--)
                _delay_ms(10);
}

int main(void)
{
        unsigned char i;
    //上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻
    PORTA=0xFF;                                                                //不用的管脚使能内部上拉电阻。
    PORTB=0xFF;
    PORTC=0xFF;
    PORTD=0xFF;

    DDRB|=(1<<LED);                                                        //PB0设为输出高电平,灯灭   
    /*
    端口引脚
    进入休眠模式时,所有的端口引脚都应该配置为只消耗最小的功耗。
    最重要的是避免驱动电阻性负载。
    在休眠模式下I/O 时钟clkI/O 和ADC 时钟clkADC 都被停止了,输入缓冲器也禁止了,从而保证输入电路不会消耗电流。
    在某些情况下输入逻辑是使能的,用来检测唤醒条件。用于此功能的具体引脚请参见“ 数字输入使能和休眠模式” 。
   如果输入缓冲器是使能的,此时输入不能悬空,信号电平也不应该接近VCC/2,否则输入缓冲器会消耗额外的电流。
   
   IO作输出(DDR=1)时,维持状态不变
        */
       
        /*
        看门狗定时器(上电默认是关闭的)
        如果系统无需利用看门狗,这个模块也可以关闭。
        若使能,则在任何休眠模式下都持续工作,从而消耗电流。
        在深层次的睡眠模式下,这个电流将占总电流的很大比重。
       
        假设看门狗定时器使能了,关闭程式如下
                1. 在同一个指令内对WDTOE 和WDE 写"1“,即使WDE 已经为"1“
                2. 在紧接的4 个时钟周期之内对WDE 写"0”
        */       
        WDTCR=(1<<WDTOE)|(1<<WDE);
        WDTCR=(0<<WDE);
        //或使用wdt.h里面的wdt_disable()函数

        /*
        模数转换器(上电默认是关闭的)
        使能时, ADC在睡眠模式下继续工作。
        为了降低功耗,在进入睡眠模式之前需要禁止ADC。
        重新启动后的第一次转换为扩展的转换。
       
        假设模数转换器使能了,关闭程式如下       
        */
       ADCSRA=(0<<ADEN);
    /*
    模拟比较器(上电默认是打开的,需要手工关闭)
    在空闲模式时,如果没有使用模拟比较器,可以将其关闭。在ADC 噪声抑制模式下也是如此。
    在其他睡眠模式模拟比较器是自动关闭的。
    如果模拟比较器使用了内部电压基准源,则不论在什么睡眠模式下都需要关闭它。否则内部电压基准源将一直使能。
   
        关闭程式如下       
        */
        ACSR=(1<<ACD);
        /*
        掉电检测BOD (由熔丝位BODEN控制)
        如果系统没有利用掉电检测器BOD,这个模块也可以关闭。
        如果熔丝位BODEN 被编程,从而使能了BOD 功能,它将在各种休眠模式下继续工作。
        在深层次的休眠模式下,这个电流将占总电流的很大比重。
       
        设置熔丝位BODEN=1 关断BOD功能
        */
       
        /*
        片内基准电压
        使用BOD、模拟比较器和ADC 时可能需要内部电压基准源。
        若这些模块都禁止了,则基准源也可以禁止。
        重新使能后用户必须等待基准源稳定之后才可以使用它。
        如果基准源在休眠过程中是使能的,其输出立即可以使用。
       
        当BOD、模拟比较器和ADC都禁止了,则基准源也自动禁止了。
        */
       
        /*
        JTAG 接口与片上调试系统
        如果通过熔丝位OCDEN使能了片上调试系统,当芯片进入掉电或省电模式时主时钟保持运行。
        在休眠模式中这个电流占总电流的很大比重。
        下面有三种替代方法:
        1 不编程OCDEN
    2 不编程JTAGEN
    3 置位MCUCSR 的JTD
        当JTAG 接口使能而JTAG TAP 控制器没有进行数据交换时,引脚TDO 将悬空。
        如果与TDO 引脚连接的硬件电路没有上拉电阻,功耗将增加。
        器件的引脚TDI 包含一个上拉电阻,因此在扫描链中无需为下一个芯片的TDO 引脚设置上拉电阻。
        通过置位MCUCSR寄存器的JTD 或不对JTAG 熔丝位编程可以禁止JTAG 接口。
       
        JTD: 禁止JTAG 接口(MCU控制与状态寄存器MCUCSR Bit7)
        此位为0 时,如果JTAGEN熔丝位被编程则JTAG 接口使能。
        如果这位为1, JTAG接口禁止。
        为了避免无意的禁止或使能JTAG接口,必须通过一个时间序列来改变JTD 位。
                应用软件必须在四个时钟周期内将期望的数值两次写入JTD。
        如果JTAG 接口没有与其他JTAG电路连接, JTD应该置位。这样做的原因是为了避免JTAG接口TDO引脚的静态电流。
       
        在软件中关闭JTAG接口的方法   
        */
        MCUCSR=(1<<JTD);
        MCUCSR=(1<<JTD);       
       
        /*
        掉电模式
        当SM2..0 为010 时, SLEEP 指令将使MCU 进入掉电模式。
        在此模式下,外部晶体停振,而外部中断、两线接口地址匹配及看门狗(如果使能的话)继续工作。
        只有外部复位、看门狗复位、BOD 复位、两线接口地址匹配中断、外部电平中断INT0 或INT1,或外部中断INT2 可以使MCU 脱离掉电模式。
        这个睡眠模式停止了所有的时钟,只有异步模块可以继续工作。
        当使用外部电平中断方式将MCU 从掉电模式唤醒时,必须保持外部电平一定的时间。
        从施加掉电唤醒条件到真正唤醒有一个延迟时间,此时间用于时钟重新启动并稳定下来。
        唤醒周期与由熔丝位CKSEL 定义的复位周期是一样的。
       
        如果在睡眠过程中发生了复位,则MCU 唤醒后从中断向量开始执行
        使能的中断可以将进入睡眠模式的MCU 唤醒,        经过启动时间,外加4个时钟周期后,MCU就可以运行中断例程了。然后返回到SLEEP 的下一条指令。
        */
        //MCUCSR|=(0<<ISC0)|(0<<ISC1)|(0<<ISC2);                //INT2 的下降沿激活中断(默认的,这句话可以不写)
        GICR|=(1<<INT0)|(1<<INT1)|(1<<INT2);                 //使能外部中断INT2
        sei();                                        //使能全局中断
        while(1)
        {
                for (i=0;i<5;i++)//LED闪动10次后进入掉电模式的睡眠状态
                {
                        delay_10ms(30);
                        PORTB&=~(1<<LED);   //点亮LED
                        delay_10ms(30);                       
                        PORTB|=(1<<LED);        //熄灭LED
                }
               
                set_sleep_mode(SLEEP_MODE_PWR_DOWN);        //设定为掉电模式
                sleep_mode();                                                        //进入睡眠状态
                /*
                也可以自行编写
                MCUCR=(0<<SM2)|(1<<SM1)|(0<<SM0);           //设定为掉电模式
                asm volatile(“sleep” : : );                                //进入睡眠状态
                */               
        }
}


SIGNAL(SIG_INTERRUPT0)//外部中断2服务程序 唤醒源
{
        PORTB&=~(1<<LED);   //点亮LED
        delay_10ms(50);
        PORTB|=(1<<LED);        //熄灭LED
        delay_10ms(10);

        /*LED长亮5秒钟,熄灭1秒钟后,退出中断服务程序,然后返回到SLEEP 的下一条指令*/       
}


SIGNAL(SIG_INTERRUPT1)//外部中断2服务程序 唤醒源
{
        PORTB&=~(1<<LED);   //点亮LED
        delay_10ms(50);
        PORTB|=(1<<LED);        //熄灭LED
        delay_10ms(10);

        /*LED长亮5秒钟,熄灭1秒钟后,退出中断服务程序,然后返回到SLEEP 的下一条指令*/       
}

SIGNAL(SIG_INTERRUPT2)//外部中断2服务程序 唤醒源
{
        PORTB&=~(1<<LED);   //点亮LED
        delay_10ms(50);
        PORTB|=(1<<LED);        //熄灭LED
        delay_10ms(10);

        /*LED长亮5秒钟,熄灭1秒钟后,退出中断服务程序,然后返回到SLEEP 的下一条指令*/       
}


/*
   程序运行效果
   万用表打到直流电流的最小档位(uA分辨率),接到开关的两头
   烧录后要把STK500拔出,否则无法测得正确的电流数据。
   
   上电后LED闪动10次后进入掉电模式的睡眠状态
               此时可断开开关
               看看万用表的读数
               然后接通开关
   按下 INT2按键,将会发现LED长亮5秒钟,熄灭1秒钟后,退回主程序,LED闪动10次后进入掉电模式的睡眠状态
   如果按下复位按键,马上复位。

   网友可以编写其他睡眠模式/开关各种模块/其他时钟源/其他电源电压来测试电流消耗情况
*/


/*
电源管理及睡眠模式
        睡眠模式可以使应用程序关闭MCU中没有使用的模块,从而降低功耗。
        AVR 具有不同的睡眠模式,允许用户根据自己的应用要求实施剪裁。
        进入睡眠模式的条件是置位寄存器MCUCR的SE,然后执行SLEEP 指令。
        具体哪一种模式( 空闲模式、ADC 噪声抑制模式、掉电模式、省电模式、Standby 模式和扩展Standby模式) 由MCUCR 的SM2、SM1 和SM0 决定。
        使能的中断可以将进入睡眠模式的MCU 唤醒。
        经过启动时间,外加4个时钟周期后,MCU就可以运行中断例程了。然后返回到SLEEP 的下一条指令。
        唤醒时不会改变寄存器文件和SRAM的内容。
        如果在睡眠过程中发生了复位,则MCU 唤醒后从中断向量开始执行
       
        需要了解AVR芯片内部不同的时钟系统及其分布,在选择合适的睡眠模式时非常有用。
       
MCU控制寄存器-MCUCR
        MCU控制寄存器包含了电源管理的控制位。
                  Bits 7, 5, 4 – SM2..0: 休眠模式选择位 2、1 和0
                这些位用于选择具体的休眠模式。
                SM2 SM1 SM0 休眠模式
               0   0   0空闲模式
               0   0   1ADC 噪声抑制模式
               0   1   0掉电模式
               0   1   1省电模式
               1   0   0保留
               1   0   1保留
               1   1   0Standby模式(1)
               1   1   1扩展Standby模式(1)
                Note:1 仅在使用外部晶体或谐振器时Standby 模式与扩展Standby 模式才可用。
               
                  Bit 6 – SE: 休眠使能
                为了使MCU 在执行SLEEP 指令后进入休眠模式, SE必须置位。
                为了确保进入休眠模式是程序员的有意行为,建议仅在SLEEP 指令的前一条指令置位SE。
                MCU 一旦唤醒立即清除SE。

关于各种睡眠模式的特点与唤醒要求,内容繁多,请参考数据手册
*/

zxq6 发表于 2008-6-26 13:51:41

光顶,不发表意见。

armok 发表于 2008-6-26 13:54:44

本想做到自动切换电流表的。

但无奈200uA的电流表的内阻是1K的,串上后AVR芯片就不能在正常的状态工作了。

那位有更好的解决方案?

另外,我目前使用的数字电流表怪得很,从电路图上也能看出,GND竟然是与 IN- 连接的。导致它只能串在地附近,不能放在电路的任何地方。这是设计电路时需要注意的。

stephon1 发表于 2008-6-26 14:22:57

经过

armok 发表于 2008-6-26 16:33:52

补充上以下的资料:

为获得更准确的检测数据,避免干扰,需要将所有IO口设置成以下之一:

1。输入,带上拉电阻。
2。输出0
3。输出1
如果是输入不带上拉电阻,静态工作电流是跳动的,并且容易受干扰。所以,将JTAG的熔丝位也取消。

armok 发表于 2008-6-27 15:02:56

哈哈,多加了几只电阻,2只三极管,1块HC4066,解决了 自动切换电流表的解决方法。

经实际测试,工作稳定可靠,大大提高了测试效率。

一会将资料整理好,重新发上来。

f117c 发表于 2009-4-22 20:16:52

很强啊,我要做一个万用表

32446975 发表于 2009-6-4 14:55:52

参考了程序,我的进入休闲模式及唤醒也成功了。原先在INTO中断中进入休闲模式又用INT0唤醒,搞了几天不成功,感觉原因应该是INT0中断没有退出,不能再次进入INT0中断。

tianwen 发表于 2009-6-19 13:43:56

//MCUCSR|=(0<<ISC0)|(0<<ISC1)|(0<<ISC2);                //INT2 的下降沿激活中断(默认的,这句话可以不写)


这行寄存器名字写错了,应该是 MCUCR

wuly 发表于 2009-6-19 17:02:53

200uA挡1K电阻大概是为了降低前置运放的成本吧,除非下点成本换微小信号运放

sangreal 发表于 2010-4-21 18:16:12

不错,做芯片测试可以借鉴

xuhaikun 发表于 2010-8-14 11:07:14

哈哈哈,休眠最好的例子啦、、、

gyd0317 发表于 2010-9-1 15:39:10

MARK

xuhaikun 发表于 2010-12-22 10:54:45

太详细了...狂顶...哈哈哈...

yl604922959 发表于 2010-12-22 16:48:29

mark

gloryzkl 发表于 2011-1-7 00:51:10

坐下慢慢看…

zhouhaiyeild 发表于 2011-6-30 10:03:30

mark

dhw5qq 发表于 2014-5-7 10:40:41

不知道你有没有用twi地址匹配试试唤醒的效果,我给你说下,我现在主机是mg16,从机是mg48,我从机是硬件iic中断,定时11s后休眠,掉电模式,测得电流是7uA左右,

dhw5qq 发表于 2014-5-7 10:42:00

唤醒后,从机电流是1.4ma。因为只有一个iic通讯,所以电流比较低,这个唤醒效果不是很理想,因为有时候唤醒了,主机和从机就不能进行通讯了,但是大部分是唤得醒!

amberfly 发表于 2014-5-7 12:28:04

恰好要做一个低功耗,休眠模式电流还不错

py-industry 发表于 2014-9-12 09:51:39

能休眠和唤醒 但是我程序只要加入WDT_off();或者是WDT_on();就自动唤醒。原因??????

py-industry 发表于 2014-9-12 09:54:20

void WDT_off(void)
{
WDR();//喂狗//
WDTCR|=(1<<WDCE)|(1<<WDE); // 置位 WDTOE 和 WDE//
WDTCR=0x00;
}

void WDT_on(void)
{
WDR();//喂狗//
WDTCR|=(1<<WDCE)|(1<<WDE);          //置位 WDTOE 和 WDE//
WDTCR|=(1<<WDE)|(1<<WDP2)|(1<<WDP1);//设定周期为1S//
}

不管起用哪个都会自动唤醒哪个细节不对??
页: [1]
查看完整版本: 【阿莫AVR芯片检测系列文章5】电源管理(工作电流、休眠电流、休眠进入与唤醒)测试器