树莓派LM35温度传感器项目:从模拟信号到数字转换的实践指南

发布时间:2026/7/28 2:49:08

树莓派LM35温度传感器项目:从模拟信号到数字转换的实践指南 1. 从数字到模拟为什么LM35是树莓派入门的好选择如果你刚接触树莓派玩过几个LED闪烁、按钮控制的数字GPIO项目可能会觉得“硬件编程不过如此”。但当你第一次尝试把现实世界中连续变化的物理量——比如温度、光照、压力——接入这个小小的电脑时一个全新的、更贴近真实物理世界的大门才真正打开。今天要聊的LM35线性温度传感器就是推开这扇门的绝佳钥匙。为什么是LM35在众多温度传感器中DS18B20这类数字传感器因其“即插即用”的特性而广受欢迎你只需要一根数据线就能通过协议读取到已经转换好的数字温度值。这很方便但也像是一个封装好的黑盒你接触不到信号转换的核心过程。而LM35不同它是一个纯粹的模拟传感器。它输出的不是一个代表温度的数字而是一个与摄氏温度成正比的模拟电压信号。树莓派本身没有模拟输入引脚要读取这个电压你必须借助一个叫做“模数转换器ADC”的桥梁。这个过程恰恰是理解嵌入式系统如何感知世界的关键。所以这节课的目标不仅仅是让一个温度计工作。我们将通过LM35亲手搭建一个从模拟信号采集、电压转换到软件读取的完整链路。你会理解为什么需要ADC如何选择和使用ADC芯片比如PCF8591或ADS1115以及如何编写代码将读取到的原始数值还原为真实的温度。这个过程里踩的每一个坑比如参考电压不稳、接线干扰、软件滤波都是未来你处理更复杂传感器如光照、气体浓度、土壤湿度的宝贵经验。准备好了吗我们开始动手。2. 核心元件解析LM35传感器与模数转换的必要性在动手接线之前我们必须先搞清楚手头的“武器”。LM35是一个三引脚器件通常封装在一个类似三极管的小黑壳里。它的三个引脚分别是VCC电源正极接5V或3.3V、VOUT模拟电压输出、GND电源地。它的核心特性是线性输出在0°C时输出0V温度每升高1°C输出电压就增加10mV即0.01V。这意味着在25°C室温下你理论上能在VOUT引脚测量到0.25V的电压。这个特性非常优雅因为它省去了复杂的线性校准公式。但问题也随之而来树莓派的GPIO引脚是数字的它只能识别高电平通常1.8V和低电平通常1.3V。它无法直接“读懂”0.25V这个电压具体是多少。这就好比一个人只有“亮”和“暗”两种视觉无法分辨“有点亮”、“比较亮”、“非常亮”的细微差别。为了获取这个连续的电压值我们必须引入一个“翻译官”——模数转换器ADC。ADC芯片的作用就是将连续的模拟电压信号按照一定的精度离散化为数字信号。这个精度由“位数”决定。一个8位的ADC如PCF8591会把参考电压比如5V分成2^8256份每一份约等于0.0195V5V/256。它能分辨的最小电压变化就是0.0195V对应到LM35就是大约1.95°C的变化这显然不够精确。而一个16位的ADC如ADS1115则能把同样的5V分成2^1665536份每份约0.000076V对应温度分辨率可达0.0076°C足以满足绝大多数精密测量需求。注意LM35的供电电压选择会影响其测量范围。当使用5V供电时其可测量范围通常是0°C至150°C输出0V至1.5V。如果使用3.3V供电其测量上限会受限于电源电压大约在0°C至100°C左右输出0V至1.0V。在树莓派项目中为了简化电源管理并与3.3V逻辑电平的ADC匹配我通常推荐使用3.3V为LM35供电。3. 硬件搭建从LM35到树莓派的信号通路设计理解了原理我们就可以开始搭建硬件电路了。这个环节是项目成功的基础接线错误或设计不当会导致读数不准甚至损坏设备。我将以最常用的ADS1115 16位ADC模块和PCF8591 8位ADC模块为例分别说明两种方案。方案一使用高精度ADS1115模块推荐ADS1115是一个I2C接口的16位ADC精度高、噪声低自带可编程增益放大器PGA非常适合测量LM35输出的微小电压。连接ADS1115到树莓派ADS1115的VDD引脚连接到树莓派的3.3V引脚引脚1或17。ADS1115的GND引脚连接到树莓派的GND引脚例如引脚6、9、14、20等。ADS1115的SCL引脚连接到树莓派的GPIO3 (SCL)引脚物理引脚5。ADS1115的SDA引脚连接到树莓派的GPIO2 (SDA)引脚物理引脚3。ADS1115的ADDR引脚通常悬空或接地这决定了其I2C地址默认为0x48。连接LM35到ADS1115LM35的VCC引脚连接到树莓派的3.3V引脚与ADS1115共用即可。LM35的GND引脚连接到树莓派的GND引脚。LM35的VOUT引脚连接到ADS1115的A0通道或其他任意通道A0-A3。方案二使用经济型PCF8591模块PCF8591是一个更便宜、更常见的8位ADC也通过I2C通信适合对精度要求不高的教学或演示场景。连接PCF8591到树莓派其VCC、GND、SCL、SDA的连接方式与ADS1115完全相同。连接LM35到PCF8591将LM35的VOUT连接到PCF8591的AIN0通道。提示无论使用哪种ADC务必确保所有设备的“地”GND都连接到树莓派的同一个GND引脚上这被称为“共地”是保证电压测量基准一致的关键。否则你测到的将是“浮空”的、无意义的电压值。接线完成后强烈建议先不要急着写代码。打开树莓派的终端使用i2cdetect -y 1命令来扫描I2C总线。如果连接正确你应该能看到ADS1115地址0x48或PCF8591地址0x48可能冲突注意跳线出现在设备列表中。这是验证硬件通信的第一步能排除90%的接线和电源问题。4. 软件环境配置与核心库安装硬件通路打通后我们需要在软件层面做好准备。树莓派默认启用了I2C接口但为了编程方便我们需要安装针对特定ADC芯片的Python库。这里以功能更强大的ADS1115为例因为其库的支持和社区资源更丰富。首先确保你的树莓派系统已更新并启用I2C接口可通过sudo raspi-config进入“Interface Options” - “I2C”启用。然后我们安装必要的库。对于ADS1115一个广泛使用的库是Adafruit_ADS1x15。它属于Adafruit CircuitPython库生态的一部分。安装步骤如下# 更新系统包列表 sudo apt update sudo apt upgrade -y # 安装Python3的pip工具如果尚未安装 sudo apt install python3-pip -y # 安装Adafruit_Blinka库这是CircuitPython在树莓派Linux上的兼容层 sudo pip3 install adafruit-blinka # 安装ADS1x15的专用库 sudo pip3 install adafruit-circuitpython-ads1x15安装过程中如果遇到速度慢或超时可以考虑使用国内的PyPI镜像源例如清华源sudo pip3 install adafruit-circuitpython-ads1x15 -i https://pypi.tuna.tsinghua.edu.cn/simple。对于PCF8591它没有像Adafruit这样官方维护的专用库。通常的做法是使用smbus2或smbus库通过I2C直接读写其寄存器来控制。安装smbus2的命令是sudo pip3 install smbus2。这种方式需要对芯片的数据手册和寄存器映射有更深的理解对于初学者门槛稍高。为了验证安装是否成功你可以创建一个简单的Python脚本尝试导入这些库而不报错。在Thonny或任何文本编辑器中新建一个文件输入import board和import busio运行看看。如果成功说明Adafruit_Blinka基础环境已就绪。5. 代码实战从原始读数到摄氏温度的完整转换环境准备好终于到了最激动人心的编码环节。我们将编写一个Python程序周期性地从ADC读取数据并将其转换为准确的温度值。这里以ADS1115为例给出详细代码和逐行解析。# lm35_ads1115.py import time import board import busio import adafruit_ads1x15.ads1115 as ADS from adafruit_ads1x15.analog_in import AnalogIn # 创建I2C总线对象 i2c busio.I2C(board.SCL, board.SDA) # 创建ADS1115对象传入I2C总线对象 ads ADS.ADS1115(i2c) # 设置增益这里选择GAIN_TWOTHIRDS对应满量程±6.144V # 因为LM35用3.3V供电最大输出约1.5V这个量程绰绰有余且能获得更高的分辨率 ads.gain ADS.GAIN_TWOTHIRDS # 创建模拟输入通道对象连接到ADS1115的A0引脚 chan AnalogIn(ads, ADS.P0) # ADS.P0 对应通道 A0 # 定义电压到温度转换的函数 def read_temperature_celsius(voltage): 根据LM35特性输出电压与摄氏温度成正比10mV/°C。 参数 voltage: 从ADC读取的电压值单位伏特 返回: 摄氏温度值 # 核心公式温度(°C) 电压(V) / 0.01 # 0.01 即 10mV/°C 转换而来 temperature_c voltage / 0.01 return temperature_c print(开始读取LM35温度传感器数据...) print({:10} {:10} {:10}.format(原始值, 电压(V), 温度(°C))) try: while True: # 从通道读取原始值和计算出的电压值 raw_value chan.value voltage chan.voltage # 使用我们的函数计算温度 temp_c read_temperature_celsius(voltage) # 打印结果格式化输出 print({:10} {:10.4f} {:10.2f}.format(raw_value, voltage, temp_c)) # 等待1秒 time.sleep(1.0) except KeyboardInterrupt: print(\n程序被用户中断。)代码关键点解析增益Gain设置ads.gain ADS.GAIN_TWOTHIRDS这一行至关重要。增益决定了ADC的满量程输入电压范围。GAIN_TWOTHIRDS对应 ±6.144V这意味着ADC能把 -6.144V 到 6.144V 的输入电压映射到其16位的输出范围-32768 到 32767。我们的LM35输出是0-1.5V的正电压在这个量程下只占用了很小一部分但16位的分辨率保证了即使在这个小范围内我们也能得到非常精细的划分从而提高测量精度。如果设置成GAIN_ONE(±4.096V) 或GAIN_TWO(±2.048V) 也可以但GAIN_TWOTHIRDS是默认且安全的初始选择。电压读取chan.voltage属性已经帮我们完成了从原始值到电压的转换。其内部计算是电压 (原始值 / 32767) * 满量程电压。其中满量程电压由增益决定本例为6.144V。我们无需手动计算。温度转换公式voltage / 0.01是核心。这里假设LM35是理想线性的。实际上LM35的精度典型值为±0.5°C在25°C时。对于更高精度的要求可以在公式中加入一个微小的偏移量进行校准例如(voltage - 0.001) / 0.01这个偏移量需要通过与标准温度计对比实测来确定。运行这个程序你应该能在终端看到每秒刷新一次的温度读数。用手捏住LM35的金属外壳观察温度值的上升这是最直接的成就感反馈。6. 精度提升与噪声处理让读数更稳定可靠当你看到温度读数后可能会发现数值并不是完全稳定而是在一个小范围内跳动比如在24.5°C到25.5°C之间波动。这不是程序写错了而是真实世界电子测量中必然存在的“噪声”。噪声来源很多电源纹波、电磁干扰、ADC自身的量化噪声、热噪声等。我们的目标不是消除噪声那不可能而是通过软件方法滤除它得到一个稳定、可信的读数。方法一移动平均滤波这是最简单有效的软件滤波方法。其原理是连续采集N个样本然后取它们的算术平均值作为最终输出。这能有效平滑随机波动。# 在循环外初始化一个列表来存储历史数据 sample_size 10 # 采样窗口大小可根据需要调整 voltage_samples [] try: while True: # 采集当前电压 current_voltage chan.voltage # 将新样本加入列表 voltage_samples.append(current_voltage) # 如果列表长度超过窗口大小移除最老的样本 if len(voltage_samples) sample_size: voltage_samples.pop(0) # 计算窗口内电压的平均值 avg_voltage sum(voltage_samples) / len(voltage_samples) # 使用平均电压计算温度 avg_temp_c read_temperature_celsius(avg_voltage) # 同时也可以输出原始瞬时值做对比 instant_temp_c read_temperature_celsius(current_voltage) print(瞬时: {:.2f}°C, 平均({}次): {:.2f}°C.format(instant_temp_c, len(voltage_samples), avg_temp_c)) time.sleep(0.5) # 可以加快采样频率 except KeyboardInterrupt: print(\n程序退出。)方法二中值滤波对于偶尔出现的、幅度很大的异常跳动尖峰脉冲移动平均会被严重干扰。中值滤波则能很好地抵抗这种“离群值”。它的原理是取N个样本将它们排序然后取中间的那个值作为输出。import statistics median_sample_size 5 # 建议用奇数如3,5,7 voltage_samples [] try: while True: current_voltage chan.voltage voltage_samples.append(current_voltage) if len(voltage_samples) median_sample_size: voltage_samples.pop(0) # 计算中值 median_voltage statistics.median(voltage_samples) median_temp_c read_temperature_celsius(median_voltage) print(中值温度({}次): {:.2f}°C.format(len(voltage_samples), median_temp_c)) time.sleep(0.5) except KeyboardInterrupt: print(\n程序退出。)在实际项目中我常常将两者结合先用一个较小的窗口比如5点进行中值滤波剔除明显的野值然后再对中值滤波的结果进行移动平均从而得到既稳健又平滑的数据。这个过程在嵌入式领域被称为“传感器数据调理”是提升产品可靠性的基本功。7. 进阶应用与项目构思不止于读数当你能稳定、准确地读取温度后这个项目就可以作为基石拓展出许多有趣的应用。这里分享几个我实践过的方向1. 本地温度数据记录仪将读取到的温度连同时间戳写入到本地的CSV文件或SQLite数据库中。你可以设置每5分钟或10分钟记录一次运行几天就能得到一份环境温度的变化曲线。结合Matplotlib库可以轻松地将数据可视化。这个项目能让你学习到文件I/O、时间处理和数据可视化的完整流程。2. 温度阈值报警系统为程序设定一个高温和低温阈值例如高于30°C或低于10°C。当温度超过阈值时让树莓派通过GPIO控制一个蜂鸣器响起或者点亮一个红色LED甚至通过连接互联网发送一封邮件或一条Telegram消息到你的手机。这引入了“事件驱动”编程和简单逻辑控制的思想。3. 结合Web服务器实现远程监控使用轻量级的Web框架如Flask在树莓派上搭建一个简单的Web服务器。创建一个网页上面动态显示当前温度并绘制实时温度曲线。这样你可以在同一局域网内的任何设备手机、电脑的浏览器上查看温度。这涉及到基础的网络编程和前后端数据交互通常用AJAX轮询或WebSocket。4. 多传感器网络与数据融合一个ADC模块通常有多个通道ADS1115有4个。你可以购买多个LM35分别放在房间的不同位置窗边、墙角、机柜内连接到同一个ADC的不同通道。在代码中轮流读取这些通道就能构建一个简单的多点温度监测网络。你甚至可以比较不同位置的温差分析房间的热量分布。提示在进行多通道读取时要注意ADC的切换时间。ADS1115在切换通道后需要短暂的稳定时间。adafruit_ads1x15库的AnalogIn对象在每次读取时会自动处理通道切换和延迟但如果你自己用底层寄存器操作就必须在切换通道后等待几毫秒再读取数据否则会读到上一个通道的值或错误的值。从读取一个简单的电压值到构建一个完整的应用系统这中间的每一步都充满了学习和探索的乐趣。LM35项目就像一把万能钥匙它开启的不仅是温度测量的大门更是通往整个物理世界数字化的大门。当你掌握了模拟信号的采集、处理和运用你会发现树莓派能做的事情远远超乎你最初的想象。

相关新闻