在一些电池产品设计中,往往需要单片机去检测电池电压的使用情况。在以往的设计中,多少设计者会利用一路AD输入口来对电池分压,然后检测分压点的电压来计算VDD的值是多少。如图所示:
采用这种方法计算VDD的优点是精度相对较高,缺点是会消耗静态电流和占用一个AD口。所以在后来的设计中,设计者往往直接把电池的电压接在MCU的VDD上,然后通过内部提供的一路或者多路参考电压来计算VDD。以利用内部1.2V作为一路AD输入为例,当设置VDD为AD转换参考的参考电压,那么在不同的VDD时,对1.2V参考电压转换的结果不一样。
如果AD为12位数字精度,那么VDD对应的值为 VDD= 1200*4095/AD转换值。其他的参考电压1.6V,2.0V,2.4V计算方式类似。一般普通的锂电池电压,在使用过程中的电压值会是3.0V~4.25V之间,低于3.0V会被做低压保护处理,不让用户继续使用该产品,以起到保护电池的作用。
因为PFS122B,内部具有多路的参考电压,1.2V,1.6V,2.0V,2.4V,3.0V,4.0V等。考虑到电池放电的低压情况,一般参考电压用到2.4V以下就可以了。因为当VDD都没有参考电压高时,参考电压的实际值肯定也不准了,这时已经失去了参考的意义。
为了比较一下看看PFS122B,采用哪种参考电压反推VDD的效果会更好,我做了一个实验。实验利用PFS122B一个IO口输出显示数据,其他只接VDD和GND,利用内部的参考电压来计算测试的VDD值。实验的ADC采样只是简单地做了16次短时间内求平均的方法。单次采集的数据并没有取中间值:
voidGet_16_AD (void)
{
word ad_temp;
word ad16;
byte cnt;
AD_Start=1;//Skip first ADC, can delete by your select
while(!AD_DONE)
{
nop;
}//
ad16=0;
cnt=16;
do
{
AD_Start=1;//Skip first ADC, can delete by your select
while(!AD_DONE)
{
nop;
}//
//
ad_temp = adcrh << 8 | adcrl;
ad16 += ad_temp >> 4;
// get_middle_adc_from_3();
//ad16 += adcr;8bit
.wdreset;
} while (--cnt);
adc_result=ad16 >> 4;// >> 4;
}
ADC初始化做了很多种设置:
void ad_init(void)
{
/*
$ ADCM /2, 12bit;
$ ADCC Enable, ADC;//PB7 通道
$ ADCRGC VDD; // */
$ ADCM 12bit,/8;
$ ADCC Enable, ADC;
switch(sys_mode)
{
case 0:
{
$ ADCRGC VDD,ADC_BG,BG_1V2; //
break;
}
case 1:
{
$ ADCRGC VDD,ADC_BG,BG_1V6; //
break;
}
case 2:
{
$ ADCRGC VDD,ADC_BG,BG_2V; //
break;
}
case 3:
{
$ ADCRGC VDD,ADC_BG,BG_2V4; //
break;
}
case 4:
{
$ ADCRGC 2V,ADC_VDD/4; // 目前看起来是这种设置,利用内部2V参考电压,转化1/4VDD效果更为理想。
break;
}
default:
{
$ ADCRGC VDD,ADC_BG,BG_1V2; //
break;
}
}
.delay 1600;//延时400us
}
实验照片结果比较,当AD转换的高电压为VDD时,直接采用内部1.2V作为一路输入的误差最大,2.4V作为一路输入的误差最小。但是这种效果,还是没有采用内部2V作为AD转换的参考高电压,利用1/4VDD作为输入读取的结果值更为接近实际值。
利用VDD做AD转换高电压,内部1.2V作为一路输入的误差约60mv。
利用VDD做AD转换高电压,内部1.6V作为一路输入的误差约50mv。
利用VDD做AD转换高电压,内部2.0V作为一路输入的误差约40mv。
利用VDD做AD转换高电压,内部1.2V作为一路输入的误差约30mv。
利用内部2V做AD转换高电压,1/4VDD作为一路输入的误差约15mv。
这可是相当的准确了,检测误差有时在10mV以内。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !