TMP117温度传感器在ESP32上的Micropython驱动实战(从接线到数据上传)
TMP117温度传感器在ESP32上的Micropython驱动实战(从接线到数据上传)
1. 项目概述与硬件准备
在物联网和智能硬件快速发展的今天,温度监测已成为众多应用场景的基础需求。TMP117作为一款高精度数字温度传感器,以其±0.1°C的测量精度和低功耗特性,成为环境监测项目的理想选择。结合ESP32的Wi-Fi能力和Micropython的易用性,我们可以快速构建一个无线温度监测系统。
所需硬件清单:
- ESP32开发板(推荐使用ESP32-WROOM-32)
- TMP117温度传感器模块
- 4.7kΩ电阻×2(用于I2C上拉)
- 面包板和杜邦线若干
TMP117采用I2C接口通信,默认地址为0x48(可通过ADDR引脚配置为其他地址)。其关键特性包括:
- 测量范围:-55°C至+150°C
- 分辨率:0.0078°C
- 工作电流:3.5μA(单次测量模式)
2. 硬件连接与I2C配置
正确的硬件连接是项目成功的第一步。ESP32与TMP117的接线方式如下:
| ESP32引脚 | TMP117引脚 | 备注 |
|---|---|---|
| 3.3V | VCC | 电源正极 |
| GND | GND | 电源地 |
| GPIO22 | SCL | I2C时钟线,需上拉 |
| GPIO21 | SDA | I2C数据线,需上拉 |
| - | ALERT | 可悬空或连接中断 |
提示:I2C总线必须连接上拉电阻(4.7kΩ),否则通信可能失败。部分开发板已内置上拉电阻,建议仍外接以确保稳定性。
连接完成后,可通过以下Micropython代码验证I2C设备是否被正确识别:
from machine import I2C, Pin i2c = I2C(scl=Pin(22), sda=Pin(21), freq=100000) devices = i2c.scan() print("发现的I2C设备地址:", [hex(addr) for addr in devices])正常情况应输出['0x48'](TMP117的默认地址)。若未发现设备,请检查:
- 电源连接是否正确
- I2C线序是否接反
- 上拉电阻是否正常工作
3. TMP117驱动开发
3.1 寄存器配置
TMP117通过寄存器进行配置和读数,主要寄存器包括:
| 寄存器地址 | 名称 | 功能描述 |
|---|---|---|
| 0x00 | TEMP_RESULT | 温度结果(只读) |
| 0x01 | CONFIGURATION | 传感器配置 |
| 0x02 | THIGH_LIMIT | 温度高阈值 |
| 0x03 | TLOW_LIMIT | 温度低阈值 |
我们需要重点关注CONFIGURATION寄存器(地址0x01),其各位定义如下:
15: MODE[1:0] - 工作模式(00=连续,01=单次,10=关闭) 13-12: CONV[1:0] - 转换周期(00=15.5ms,01=125ms,10=250ms,11=500ms) 11-9: AVG[1:0] - 平均采样次数(00=无,01=8次,10=32次,11=64次) 8: T/nA - 报警极性(0=低电平,1=高电平) 7: POL - 报警模式(0=窗口比较,1=超限比较) 6: DR/ALERT - 数据就绪/报警选择 5: SOFT_RESET - 软件复位(写1触发) 4-0: 保留3.2 Micropython驱动实现
创建一个tmp117.py文件,实现完整的驱动功能:
from machine import I2C import time class TMP117: def __init__(self, i2c, address=0x48): self.i2c = i2c self.address = address self._config_reg = 0x0220 # 默认配置:连续模式,15.5ms转换周期 def write_register(self, reg, data): """写入16位寄存器""" self.i2c.writeto_mem(self.address, reg, bytes([(data >> 8) & 0xFF, data & 0xFF])) def read_register(self, reg): """读取16位寄存器""" data = self.i2c.readfrom_mem(self.address, reg, 2) return (data[0] << 8) | data[1] def reset(self): """软件复位传感器""" self.write_register(0x01, 0x8000) time.sleep_ms(20) def configure(self, mode=0, conv=0, avg=0): """配置传感器工作模式 :param mode: 0=连续模式,1=单次模式,2=关闭 :param conv: 转换周期 0=15.5ms, 1=125ms, 2=250ms, 3=500ms :param avg: 平均次数 0=无, 1=8次, 2=32次, 3=64次 """ config = (mode & 0x03) << 13 | (conv & 0x03) << 10 | (avg & 0x03) << 5 self.write_register(0x01, config) self._config_reg = config def read_temp(self): """读取温度值(摄氏度)""" raw_temp = self.read_register(0x00) return raw_temp * 0.0078125 # 转换为摄氏度 def set_limits(self, high=30.0, low=10.0): """设置温度报警阈值""" high_raw = int(high / 0.0078125) low_raw = int(low / 0.0078125) self.write_register(0x02, high_raw) self.write_register(0x03, low_raw)4. 数据采集与网络传输
4.1 基础数据采集示例
使用驱动类进行温度采集的简单示例:
from machine import I2C, Pin from tmp117 import TMP117 import time i2c = I2C(scl=Pin(22), sda=Pin(21), freq=100000) sensor = TMP117(i2c) # 配置为单次模式,250ms转换周期,8次平均 sensor.configure(mode=1, conv=2, avg=1) while True: sensor.write_register(0x01, sensor._config_reg | 0x8000) # 触发单次测量 while not (sensor.read_register(0x01) & 0x0080): # 等待数据就绪 time.sleep_ms(10) temp = sensor.read_temp() print("当前温度: %.2f°C" % temp) time.sleep(5) # 每5秒测量一次4.2 通过MQTT上传数据
将温度数据发布到MQTT服务器(以Adafruit IO为例):
import network from umqtt.simple import MQTTClient import ubinascii # Wi-Fi配置 WIFI_SSID = "your_wifi" WIFI_PASS = "your_password" # MQTT配置 MQTT_SERVER = "io.adafruit.com" MQTT_PORT = 1883 MQTT_USER = "your_username" MQTT_KEY = "your_aio_key" MQTT_TOPIC = b"your_username/feeds/temperature" def connect_wifi(): sta_if = network.WLAN(network.STA_IF) if not sta_if.isconnected(): print("正在连接Wi-Fi...") sta_if.active(True) sta_if.connect(WIFI_SSID, WIFI_PASS) while not sta_if.isconnected(): time.sleep(0.5) print("网络配置:", sta_if.ifconfig()) def publish_temp(temp): client = MQTTClient(ubinascii.hexlify(machine.unique_id()), MQTT_SERVER, port=MQTT_PORT, user=MQTT_USER, password=MQTT_KEY) client.connect() client.publish(MQTT_TOPIC, str(temp).encode()) client.disconnect() # 主循环 connect_wifi() while True: temp = sensor.read_temp() print("发布温度:", temp) publish_temp(temp) time.sleep(60) # 每分钟发布一次4.3 Web服务器实时显示
创建一个简单的Web服务器显示当前温度:
import socket import network def start_web_server(): sta_if = network.WLAN(network.STA_IF) addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] s = socket.socket() s.bind(addr) s.listen(1) print("监听地址:", sta_if.ifconfig()[0]) while True: conn, addr = s.accept() print("客户端连接:", addr) temp = sensor.read_temp() html = """<html><head><meta http-equiv="refresh" content="5"></head> <body><h1>当前温度: %.2f°C</h1></body></html>""" % temp conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') conn.send(html) conn.close() start_web_server()5. 进阶应用与优化
5.1 低功耗设计
对于电池供电的应用,优化功耗至关重要:
- 使用单次测量模式:配置
mode=1,仅在需要时触发测量 - 调整转换周期:根据应用需求选择最长的合适周期(如500ms)
- ESP32深度睡眠:在两次测量间使ESP32进入深度睡眠
import machine # 配置传感器为单次模式 sensor.configure(mode=1, conv=3) # 单次模式,500ms转换 while True: sensor.write_register(0x01, 0x8000) # 触发测量 time.sleep_ms(600) # 等待测量完成 temp = sensor.read_temp() print("温度:", temp) # 保存数据到文件或发送到服务器... # 进入深度睡眠10分钟 print("进入深度睡眠...") machine.deepsleep(10*60*1000) # 毫秒5.2 数据校准与滤波
虽然TMP117本身精度很高,但在特殊环境下可能需要校准:
# 简单的两点校准 def calibrate(temp1_actual, temp1_measured, temp2_actual, temp2_measured): """计算校准系数""" gain = (temp2_actual - temp1_actual) / (temp2_measured - temp1_measured) offset = temp1_actual - gain * temp1_measured return gain, offset # 应用校准 gain, offset = 1.02, -0.5 # 示例值,需实际校准 calibrated_temp = raw_temp * gain + offset对于波动较大的环境,可添加软件滤波:
class MovingAverage: def __init__(self, size=5): self.size = size self.buffer = [] def add(self, value): self.buffer.append(value) if len(self.buffer) > self.size: self.buffer.pop(0) return sum(self.buffer) / len(self.buffer) filter = MovingAverage(5) while True: raw_temp = sensor.read_temp() smooth_temp = filter.add(raw_temp) print("原始: %.2f, 平滑: %.2f" % (raw_temp, smooth_temp)) time.sleep(1)5.3 多传感器组网
通过I2C地址配置,可以连接多个TMP117传感器:
- 将不同传感器的ADDR引脚连接到不同电平(GND/VCC/SCL/SDA)
- 对应的地址变化如下:
| ADDR连接 | I2C地址 |
|---|---|
| GND | 0x48 |
| VCC | 0x49 |
| SDA | 0x4A |
| SCL | 0x4B |
读取多个传感器的示例:
sensors = { "室内": TMP117(i2c, 0x48), "室外": TMP117(i2c, 0x49) } while True: for location, sensor in sensors.items(): temp = sensor.read_temp() print("%s温度: %.2f°C" % (location, temp)) time.sleep(10)