Arduino Mega 2560测量电压与ADC精度

Arduino Mega 2560能够读取0 ~ 5V的电压,并转换为10bit0~1023级的数字信号。这怎么理解呢?

如上图,若分辨率为2bit(即) ,意味着将5V分为0~3级的数字信号,每级精度是5V /4 = 1250mV。如果分辨率为10bit,即0~1023,每级是5V / 1024 = 4.88mV;如果是12bit,即0~4096,每级是5V / 4096 = 1.22mV。分辨率越高,每级分得越小,精度就越高。

得到0~1023级测量结果后,在程序内简单转化一下(没有复杂函数,只用乘除法),就能直观读出电压。接线图如下:

问题来了,怎样显示电压呢?这里使用最简单的IDE串口监视器,连着开发板,直接在电脑屏幕上显示,但我们先要使用Serial.begin()启动串口通信,然后通过Serial.print()将电压在屏幕打印出来:

/*
 作者:Ardui.Co
 效果:串口显示模拟端口的电压值
 版本:1.0
 更新时间:2017年1月8日
*/
void setup()
{
  Serial.begin(9600); //指定串口通讯比特率为9600
}
void loop()
{
  int v = analogRead(A0);  //从A0口读取电压,模拟端口电压测量范围为0-5V,返回的值为0-1024
  float volt = v * (5.0 / 1024.0); //将返回值换算成电压
  Serial.print(volt);  //串口输出电压值
  Serial.println(" V");  //输出单位,并且换行
  delay(1000);  //输出后等待1s,降低刷新速度
}

通过A0读取电压范围不能超过5V,否则会损坏开发板,但要测量更高的电压怎么办?其实,我们可以通过分压电路来实现:

根据欧姆定律,Va0 = V *  R1/(R1+R2) = V * 10/20 = 1/2 V

即: V =  2 Va0

因此调整一下换算语句就能得出实际电压:

float volt = v * (5.0 / 1024.0) * 2

但经过分压电路的测量会降低分辨率(R1+R2)/ R1倍(上述电路为2倍),如果分压式电阻R1 = 10KR2 = 20K,可以测量0 ~ 15V,但分辨率降低3倍。换句话说,分压测量越高的电压,分辨率就越底。

 

我们会用温度传感器实验,来介绍ADC的分辨率,同时会学到怎样利用Arduino内部参考电压提高测量精度。

LM35是美国国家半导体(现被TI收购)推出的精密温度传感,其信号输出为模拟量:电压值与温度(摄氏)呈正比。不仅体积非常小(常见TO-92封装),而且不需额外的校正,就能获得较高的精度。

其主要特性:
供电电压:4~35V
工作范围:与芯片有关,LM35A-55~150°C 常见LM35D0~100°C
测量范围:与封装和电路有关,常用TO-922 ~150°C
测量精度:与芯片有关,LM35A性能最优,这次实验用的LM35D最差,其典型值为±0.8°C,最大值±2°C

电压与温度的关系: Vout = Temperature × 10mV/°C

想了解更多,可以参考官方 DataSheet。接线方式如下:

电压转换方式:

Vin为输入(被测量)电压;Vref是参考电压,若不设置就是供电电压,Arduino Mega 25605Vresolution是模拟端口的ADC bitArduino Mega 2560模拟端口为10bitResult为模拟端口的测量结果,数值为0~1023。程序如下:

/*
  作者:Ardui.Co
  效果:LM35 简单温度测量
  版本:1.0
  更新时间:2017年1月9日
*/
int LM35 = A0; //指定A0端口读取LM35
float Vin; //存储传感器电压
float temperature; //存储温度测量结果

void setup()
{
  Serial.begin(9600); //初始化串口连接
}
void loop()
{
  Vin = analogRead(LM35) * 5.0 / 1024; //计算出A0的电压,单位为V
  temperature = Vin * 1000.0 / 10.0; //将A0电压要转换成mV,根据LM35转换系数10mV/°C,除以10,得出温度
  Serial.print("Temperature: "); //在串口监视器输出结果
  Serial.print(temperature);
  Serial.println(" *C");
  delay(500); //延时0.5s
}

ADC测量精度问题:

对于5V参考电压来说,每级为5V / 1024 = 4.88mV,转化为温度,每级分辨率就是0.488 °C。如果环境温度为TArduino Mega 2560的测量结果是0.488 Result,但Result0 ~ 1023的正整数,误差τ就是

τ = T mod 0.488mod为求余运算)

Arduino Mega 2560内置了1.1v参考电压,使用这个参考电压,每级为1.1V / 1024  = 1.07mV,每级分辨率提高到0.107°C

如果环境温度为10°C,取5V参考电压的分辨率为0.24°C,取1.1V参考电压则为0.049°C;如果环境温度为25°C,取5V参考电压的误差为0.112°C,取1.1V参考电压则为0.069°C

接线不变,调整一下程序,引入Arduino的内部参考电压:

/*
  作者:Ardui.Co
  效果:LM35 使用1.1内部参考电压提高分辨率
  版本:1.0
  更新时间:2017年1月9日
*/
int LM35 = A0; //指定A0端口读取LM35
float Vin; //存储传感器电压
float temperature; //存储温度测量结果

void setup()
{
  analogReference(INTERNAL); //使用内部参考电压
  Serial.begin(9600); 
}
void loop()
{
  Vin = analogRead(LM35) * 1.1 / 1024; //计算出A0的电压,单位为V
  temperature = Vin * 1000.0 / 10.0; //将A0电压要转换成mV,根据LM35转换系数10mV/°C,除以10,得出温度
  Serial.print("Temperature: "); //在串口监视器输出结果
  Serial.print(temperature);
  Serial.println(" *C");
  delay(500);
}

参考电压稳定性:

由于参考电压跟Vin和温度成正比,实际中的电源电压往往十分不稳定,电池电压会随着电量变化(比如:单个锂离子放电电压约为4.25V ~ 2.95V),开关电源会有50 ~ 200mV纹波,常见的USB电源在不同负载上约有±4%的变化。

但别以为用Arduino Mega 2560内部参考电压就万事大吉,其误差更高达5%。因此,使用内部基准源在提高分辨能力的同时,也引入了额外的测量误差,所以要用稳定性高的参考电压。

其实,也有一个折中的方案。Arduino Mega 2560内部提供了一块LDO(低压差稳压IC),为3.3V端口供电。LDO一般为德州仪器的 LP2985-33DBVR,其误差小于1.5%,用它来做外部参考电压,相对5V来说分辨率更高,相对1.1V内部参考电压来说,测量误差更小。

要使用外部参考电压,将Aref连接到3.3V端口:

我们将3.3V的端口跟Aref链接,并在内部程序中声明:

/*
  作者:Ardui.Co
  效果:LM35 使用3.3外部参考电压提高分辨率
  版本:1.0
  更新时间:2017年1月10日
*/
int LM35 = A0; //指定A0端口读取LM35
float Vin; //存储传感器电压
float temperature; //存储温度测量结果

void setup()
{
  analogReference(EXTERNAL); //使用内部参考电压
  Serial.begin(9600); 
}
void loop()
{
  Vin = analogRead(LM35) * 3.3 / 1024; //计算出A0的电压,单位为V
  temperature = Vin * 1000.0 / 10.0; //将A0电压要转换成mV,根据LM35转换系数10mV/°C,除以10,得出温度
  Serial.print("Temperature: "); //在串口监视器输出结果
  Serial.print(temperature);
  Serial.println(" *C");
  delay(500);
}

我们还可以Aref连接到Arduino开发板之外的参考源上,以获取更精确的测量结果。

另外,要提高的分辨率,除了改变参考电压,也可以采用高位数的ADC芯片,不少精密ADC可达16bit以上分辨率。

参考链接


发布者

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注