【实验报告】基于Arduino UNO的数字温度计
AcFan-AK
2025年10月19日 04:54

基础教程8 Arduino温度计与参考电压精度

潘叔的DIY世界

入错行的工程师

20 人赞同了该文章

本专栏内容经修订后,已在豆瓣阅读集结成书出版:

https://read.douban.com/ebook/106875966/​read.douban.com/ebook/106875966/

read.douban.com/ebook/106875966/

第8课我们会用温度传感器实验,来介绍 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 UNO 为 5V;resolution 是模拟端口的 ADC bit,Uno 模拟端口为10bit,Result 为 模拟端口的测量结果,数值为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。如果环境温度为 T ,Arduino Uno 的测量结果是 0.488 Result ,但 Result 是 0 ~ 1023 的正整数,误差 τ 就是

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

Arduino Uno 内置了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 Uno 内部参考电压就万事大吉,其误差更高达 5%。因此,使用内部基准源在提高分辨能力的同时,也引入了额外的测量误差,所以要用稳定性高的参考电压。

其实,也有一个折中的方案。Arduino Uno 内部提供了一块 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 以上分辨率,我们会在提高篇中来讲解。

练习6.1:尝试结合第6课的内容,根据温度来控制风扇的速度。