首先让我们来探究下,什么是带隙电压。
1、我们需要了解ADC测量的影响因素,举个简单的例子。
我们给单片机供电是2.8V,此时用ADC去测量一个1.3V,ADCRH最后得到的值,可能就是142.
如果单片供电是3.3V,这时候再去测量1.3V,ADCRH最后得到的值可能就不再是142了.
如果是5V,得到的数据可能更低。
以上这个简单的例子,相信已经能说明一个简单的问题,ADC得到的数据,会随着供电电压的改变而改变。为了解决这个问题,人们想出了使用外部基准的办法,大致的方法就是使用两个ADC通道,一个通道测量外部基准(如TI431),一个通道进行对目标的测量。知道了基准值,就可以得到一个相对准确的测量值。但这种方法需要占用两个ADC通道,并且需要外部器件,成本较高。这时候就可以使用单片机内置的带隙电压了~
2、带隙电压的构成。
大概如下图所示。R3/R4使用正负温度系数材料,是为了避免温度对分压电阻造成的影响,这样温差造成的影响可以进行互补,导致带隙电压不稳。
3、N76E003的带隙电压。
常温下,所有N76E003的Band-gap电压值会校准在1.17V ~ 1.27 V内。如果想要知道每颗N76E003的
Band-gap实际电压值,可以通过读取UID地址后的2个bytes值来确认。 UID 后的2个bytes储存Band-gap
的实际值,总共12个有效bit。第一个byte是高8位,第二个byte的低4位为12 bit的低4位。
由上所知,我们知道了N76间隙电压大致范围,以及UID中存储着实际数据,接下来我们将在程序中看下,如何得到间隙电压。(以下程序源自新唐官方例程修改)
需要注意的是:
对于N76E003,为了得到更准确的内部带隙电压(band-gap)输入ADC转换值,建议在读取时,放弃模块使能
后的头三笔资料。而后,只要不关闭ADC模块, ADC转换结果都是如规格所列。提醒:程序中如果关闭
了ADC模块,请记得下次打开时,需要再次丢弃3笔。
转换的公式:VDD=4096(UID中的带隙电压/ADC测量得到的带隙电压);*
用上式的比例系数,在普通测量时,就可以用修来正测量值。
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
double Bandgap_Voltage,ADC_Voltage; //please always use "double" mode for this
unsigned char xdata ADCdataH[5], ADCdataL[5];
int ADCsumH=0, ADCsumL=0;
unsigned char ADCavgH,ADCavgL;
UINT8 BandgapHigh,BandgapLow,BandgapMark;
double Bandgap_Value,Bandgap_Voltage_Temp;
double Coe,bgvalue,RC_value;//比例系数,测量带隙电压
/*
程序功能:读取UID中带隙电压值;通过ADC,测量实际的带隙电压;得到比例系数COE;
本程序需要放在ADC正常测量前。
*/
void READ_BANDGAP()
{
unsigned int i;
set_IAPEN;
IAPCN = READ_UID;
IAPAL = 0x0d;
IAPAH = 0x00;
set_IAPGO;
BandgapLow = IAPFD;
BandgapMark = BandgapLow&0xF0;
if (BandgapMark==0x80)
{
BandgapLow = BandgapLow&0x0F;
IAPAL = 0x0C;
IAPAH = 0x00;
set_IAPGO;
BandgapHigh = IAPFD;
Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
Bandgap_Voltage_Temp = Bandgap_Value*3/4;
Bandgap_Voltage = Bandgap_Voltage_Temp - 33; //the actually banggap voltage value is similar this value.
}
if (BandgapMark==0x00)
{
BandgapLow = BandgapLow&0x0F;
IAPAL = 0x0C;
IAPAH = 0x00;
set_IAPGO;
BandgapHigh = IAPFD;
Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
Bandgap_Voltage= Bandgap_Value*3/4;
}
if (BandgapMark==0x90)
{
IAPAL = 0x0E;
IAPAH = 0x00;
set_IAPGO;
BandgapHigh = IAPFD;
IAPAL = 0x0F;
IAPAH = 0x00;
set_IAPGO;
BandgapLow = IAPFD;
BandgapLow = BandgapLow&0x0F;
Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
Bandgap_Voltage= Bandgap_Value*3/4;
}
clr_IAPEN;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
Enable_ADC_BandGap; //使能ADC带隙电压
CKDIV = 0x02; // IMPORTANT!! Modify system clock to 4MHz ,then add the ADC sampling clock base to add the sampling timing.
for(i=0;i<5;i++) //采样5次,不要前面三次
{
clr_ADCF;
set_ADCS;
while(ADCF == 0);
ADCdataH[i] = ADCRH;
ADCdataL[i] = ADCRL;
}
CKDIV = 0x00;
//--------均值滤波--------------------------------------------
for(i=2;i<5;i++) // use the last 3 times data to make average
{
ADCsumH = ADCsumH + ADCdataH[i];
ADCsumL = ADCsumL + ADCdataL[i];
}
ADCavgH = ADCsumH/3;
ADCavgL = ADCsumL/3;
bgvalue = (ADCavgH<<4) + ADCavgL;
Coe=(Bandgap_Voltage/bgvalue);
ADCsumH = 0;
ADCsumL = 0;
}
void ADC_ISR (void) interrupt 11
{
if(ADCF)
{
clr_ADCF;//清除ADC转化完成标志,进行下一次转换
set_ADCS;//当单次转换完成后,ADCS会硬件置0,需要重新使能
RC_value= (ADCRH<<4) + ADCRL;//得到ADC转换值
ADC_Voltage=RC_value*Coe;
}
}
void main (void)
{
Set_All_GPIO_Quasi_Mode;
READ_BANDGAP();
Enable_ADC_AIN6;//配置使能P03,作为AIN6。
//P04_FALLINGEDGE_TRIG_ADC;// 使用P04下降沿触发中断,使 用外部触发时,可以不使能ADCS。
set_EADC;//使能ADC中断
EA = 1;
set_ADCS;//使能ADCS,启动ADC测量
while(1);
}
程序的大概流程,先使用 READ_BANDGAP();函数,得到UID中的带隙电压,再通过ADC测量一次带隙电压,最终得到Coe(系数),后使能相关ADC通道,在中断中,测量值*Coe得到修正的数据。