【阿莫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。
关于各种睡眠模式的特点与唤醒要求,内容繁多,请参考数据手册
*/ 光顶,不发表意见。 本想做到自动切换电流表的。
但无奈200uA的电流表的内阻是1K的,串上后AVR芯片就不能在正常的状态工作了。
那位有更好的解决方案?
另外,我目前使用的数字电流表怪得很,从电路图上也能看出,GND竟然是与 IN- 连接的。导致它只能串在地附近,不能放在电路的任何地方。这是设计电路时需要注意的。 经过 补充上以下的资料:
为获得更准确的检测数据,避免干扰,需要将所有IO口设置成以下之一:
1。输入,带上拉电阻。
2。输出0
3。输出1
如果是输入不带上拉电阻,静态工作电流是跳动的,并且容易受干扰。所以,将JTAG的熔丝位也取消。 哈哈,多加了几只电阻,2只三极管,1块HC4066,解决了 自动切换电流表的解决方法。
经实际测试,工作稳定可靠,大大提高了测试效率。
一会将资料整理好,重新发上来。 很强啊,我要做一个万用表 参考了程序,我的进入休闲模式及唤醒也成功了。原先在INTO中断中进入休闲模式又用INT0唤醒,搞了几天不成功,感觉原因应该是INT0中断没有退出,不能再次进入INT0中断。 //MCUCSR|=(0<<ISC0)|(0<<ISC1)|(0<<ISC2); //INT2 的下降沿激活中断(默认的,这句话可以不写)
这行寄存器名字写错了,应该是 MCUCR 200uA挡1K电阻大概是为了降低前置运放的成本吧,除非下点成本换微小信号运放 不错,做芯片测试可以借鉴 哈哈哈,休眠最好的例子啦、、、 MARK 太详细了...狂顶...哈哈哈... mark 坐下慢慢看… mark 不知道你有没有用twi地址匹配试试唤醒的效果,我给你说下,我现在主机是mg16,从机是mg48,我从机是硬件iic中断,定时11s后休眠,掉电模式,测得电流是7uA左右, 唤醒后,从机电流是1.4ma。因为只有一个iic通讯,所以电流比较低,这个唤醒效果不是很理想,因为有时候唤醒了,主机和从机就不能进行通讯了,但是大部分是唤得醒! 恰好要做一个低功耗,休眠模式电流还不错 能休眠和唤醒 但是我程序只要加入WDT_off();或者是WDT_on();就自动唤醒。原因?????? 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]