Arduino Mega 2560
能够读取0 ~ 5V
的电压,并转换为10bit
即0~1023
级的数字信号。这怎么理解呢?
如上图,若分辨率为2bit
(即2²
) ,意味着将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()
将电压在屏幕打印出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* 作者: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
因此调整一下换算语句就能得出实际电压:
1 |
float volt = v * (5.0 / 1024.0) * 2 |
但经过分压电路的测量会降低分辨率(R1+R2)/ R1
倍(上述电路为2
倍),如果分压式电阻R1 = 10K
,R2 = 20K
,可以测量0 ~ 15V
,但分辨率降低3
倍。换句话说,分压测量越高的电压,分辨率就越底。
我们会用温度传感器实验,来介绍ADC
的分辨率,同时会学到怎样利用Arduino
内部参考电压提高测量精度。
LM35
是美国国家半导体(现被TI
收购)推出的精密温度传感,其信号输出为模拟量:电压值与温度(摄氏)呈正比。不仅体积非常小(常见TO-92
封装),而且不需额外的校正,就能获得较高的精度。
其主要特性:
供电电压:4~35V
工作范围:与芯片有关,LM35A
为-55~150°C
常见LM35D
为0~100°C
测量范围:与封装和电路有关,常用TO-92
为2 ~150°C
测量精度:与芯片有关,LM35A
性能最优,这次实验用的LM35D
最差,其典型值为±0.8°C
,最大值±2°C
电压与温度的关系: Vout = Temperature × 10mV/°C
想了解更多,可以参考官方 DataSheet。接线方式如下:
电压转换方式:
Vin
为输入(被测量)电压;Vref
是参考电压,若不设置就是供电电压,Arduino Mega 2560
为5V
;resolution
是模拟端口的ADC bit
,Arduino Mega 2560
模拟端口为10bit
,Result
为模拟端口的测量结果,数值为0~1023
。程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* 作者: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
。如果环境温度为T
,Arduino Mega 2560
的测量结果是0.488 Result
,但Result
是0 ~ 1023
的正整数,误差τ
就是
τ = T mod 0.488 (mod
为求余运算)
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
的内部参考电压:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* 作者: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
链接,并在内部程序中声明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* 作者: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
以上分辨率。