[TOC]
測(cè)量電池電量原理
對(duì)于鋰電池而言洁墙,可以用電池電壓近似代替指示電池電量癌别,一般來說單節(jié)鋰電池電壓范圍是3~4.2v歼争,測(cè)得電池電壓后做百分比計(jì)算即可响迂,因此關(guān)鍵即在于如何測(cè)量電池電壓
測(cè)電池電壓可能方案
- 初始思路 直接ADC測(cè)量電池電壓
ADC測(cè)量的前提是有一個(gè)穩(wěn)定標(biāo)準(zhǔn)的參考電壓Vref考抄,默認(rèn)Arduino的Vref取的是Vcc電壓,而在電池供電下這個(gè)Vcc本身就是變化的蔗彤,也不能用自己去參考自己測(cè)量
結(jié)論 不可行
- 進(jìn)階思路 電池正負(fù)極并聯(lián)電阻分壓法測(cè)電壓
這個(gè)方法原理上可行川梅,原因是AVR單片機(jī)內(nèi)部有一個(gè)1.1V的基準(zhǔn)參考電壓,可以調(diào)用如下接口使能
analogReference(INTERNAL)然遏;use internal 1.1v as Avref
//analogReference(DEFAULT); use AVcc as AVref
但電阻會(huì)造成額外持續(xù)的功耗贫途,而電池供電情況下本身往往就是比較強(qiáng)調(diào)低功耗的,另外1.1V電壓較低待侵,造成電阻也必須設(shè)置為將VCC分壓得較小丢早,ADC量程小電阻值也相差大,造成精度較低秧倾,而由于電池本身有內(nèi)阻且會(huì)變化怨酝,進(jìn)一步造成精度下降
結(jié)論:不堪用
- 推薦方法 正確使用內(nèi)部1.1V基準(zhǔn)電壓
敏銳的同學(xué)會(huì)發(fā)現(xiàn)AVR單片機(jī)設(shè)置的內(nèi)部1.1V基準(zhǔn)電壓應(yīng)該不是用于直接作為Vref使用的,因?yàn)閷?duì)于VCC 5V的情況下那先,很少有直接測(cè)量低于1.1v外部電壓的情況农猬,實(shí)際上,這個(gè)內(nèi)部的1.1v基準(zhǔn)電壓的一個(gè)主要用途就是用于電池供電下測(cè)量電池電壓的售淡,只是方法有點(diǎn)巧妙斤葱。
ADC的計(jì)算方法很簡(jiǎn)單如下:
ADC = Vin/Vref * 2^n
其中可以看到,其實(shí)Vin和Vref是對(duì)稱的揖闸,只需要保證其中一個(gè)值是基準(zhǔn)的揍堕,就可以得到另外一個(gè)值。
也就是說汤纸,我們可以設(shè)外部VCC為Vref衩茸,去“測(cè)量”1.1V的基準(zhǔn)電壓的ADC數(shù)值來反推得到外部VCC的實(shí)際值
是不是很巧妙?這樣不需要任何額外的外部電路蹲嚣,理論可以測(cè)得1.1v以上任意大小電壓递瑰!
換句話說,這樣是限制了ADC的測(cè)量下限來換取測(cè)量上限隙畜,這也是為什么內(nèi)部基準(zhǔn)電壓設(shè)置為1.1v這么小的原因抖部,因?yàn)榧词箤?duì)于普通的1.5v鎳鉻電池低電量下也不會(huì)低于1.1v,atmel的工程師真的是考慮很周到~
代碼
這里直接給出一個(gè)函數(shù)议惰,大家可以直接加到Arduino里調(diào)用即可慎颗,由于Arduino里沒有給出設(shè)置ADC采樣口的接口(即將Vin設(shè)置為內(nèi)部1.1v),因此這里直接配置AVR的寄存器來實(shí)現(xiàn)
#include "Arduino.h" //用于包含如ADMUX等寄存器的宏
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define ADMUX_VCCWRT1V1 (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1))
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
#define ADMUX_VCCWRT1V1 (_BV(MUX5) | _BV(MUX0))
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
#define ADMUX_VCCWRT1V1 (_BV(MUX3) | _BV(MUX2))
#else
#define ADMUX_VCCWRT1V1 (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1))
#endif
float Read_Volts(void)
{
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
if (ADMUX != ADMUX_VCCWRT1V1)
{
ADMUX = ADMUX_VCCWRT1V1;
// Bandgap reference start-up time: max 70us
// Wait for Vref to settle.
delayMicroseconds(350);
}
// Start conversion and wait for it to finish.
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA,ADSC)) {};
// Result is now stored in ADC.
// Calculate Vcc (in V)
float vcc = 1.1*1024.0 / ADC;
return vcc;
}
注意一定需要包含#include "Arduino.h"
,包含基本的寄存器宏。
atmega寄存器說明
上述代碼中核心一步是對(duì)ADC多路選擇寄存器ADMUX的配置俯萎,這里給出具體說明
其中REFS1和REFS0用于設(shè)置Vref傲宜,這里應(yīng)該配置為01對(duì)應(yīng)Vcc口
MUX3..0用于選擇ADC的輸入Vin,這里應(yīng)配置為內(nèi)部1.1v對(duì)應(yīng)的1110