深夜提醒

现在是深夜,建议您注意休息,不要熬夜哦~

🏮 🏮 🏮

新年快乐

祝君万事如意心想事成!

share-image
ESC

ESP32 连接 DS18B20 温度传感器

上一篇把 ESP32 连上 WiFi 和蓝牙之后,接下来想接点传感器玩玩。先从最常见的温度传感器 DS18B20 开始,它的优点是数字输出、一根总线可以挂多个设备、精度也还不错。

1. 所需材料

  • ESP32 开发板一块
  • DS18B20 温度传感器模块(或裸传感器)
  • 4.7kΩ 电阻一个(上拉用)
  • 杜邦线若干

2. 接线方式

DS18B20 是三脚封装,接线如下:

DS18B20 ESP32
VCC 3.3V
GND GND
DATA GPIO13

注意:DATA 和 3.3V 之间必须接一个 4.7kΩ 上拉电阻,否则 OneWire 总线不稳定,经常读不到设备。

        4.7kΩ
3.3V ───\/\/\/───┬──── DATA (GPIO13)

DS18B20 ─┴────
VCC ──────────────── 3.3V
GND ──────────────── GND

实际接线照片:

温度计读数

3. 读取温度代码

MicroPython 自带 onewireds18x20 模块,不需要额外安装。

from machine import Pin
import onewire
import ds18x20
import time

ds_pin = Pin(13)
ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))


def read_temperature():
roms = ds_sensor.scan()
if not roms:
print('未检测到 DS18B20 设备,请检查接线')
return None

ds_sensor.convert_temp()
time.sleep_ms(750) # 等待转换完成

temps = []
for rom in roms:
temp = ds_sensor.read_temp(rom)
if isinstance(temp, float):
temps.append(round(temp, 2))
return temps


while True:
temps = read_temperature()
if temps:
print('当前温度:', temps, '°C')
time.sleep(1)

代码说明:

  • scan() 扫描 OneWire 总线上的设备,返回每个设备的 64 位 ROM 地址。
  • convert_temp() 向所有设备发送温度转换命令。
  • DS18B20 默认 12 位精度转换时间约 750ms,所以必须 sleep_ms(750)
  • read_temp(rom) 读取指定设备的温度。

4. 识别传感器型号

运行下面命令可以读取 ROM 地址和家族码:

from machine import Pin
import onewire, ds18x20, binascii

ow = onewire.OneWire(Pin(13))
ds = ds18x20.DS18X20(ow)
roms = ds.scan()
for rom in roms:
print('ROM:', binascii.hexlify(rom), 'Family:', hex(rom[0]))

我手上这颗输出:

ROM: b'2824bb020002249f'  Family: 0x28

家族码 0x28 就是 DS18B20。如果是 0x10 则是老款的 DS18S20。

5. 实际读数

串口输出:

当前温度: [32.19] °C
当前温度: [32.19] °C
当前温度: [32.12] °C

实际拍摄的温度计读数:

接线实物图

这个温度是室温加手指捏着传感器的余温,所以比正常室温偏高一点。

6. 常见问题

  • 读不到设备:先检查上拉电阻有没有接,杜邦线有没有插紧。
  • 温度偶尔跳 85°C:这是 DS18B20 的上电复位默认值,通常是因为读取时转换还没完成,把 sleep_ms 时间加长到 1000ms。
  • 多个传感器scan() 会返回多个 ROM,convert_temp() 一次触发全部设备,然后逐个 read_temp(rom) 即可。

7. 实时上传到博客数据库

blog-api 已经提供了温度写入接口,不需要再写后端代码。接口信息:

  • 写入:POST https://your-api-domain.com/api/v1/temperature/realtime
  • 认证:Header Authorization: Bearer sk_xxx
  • 请求体:
{
"value": 26.56,
"timestamp": 1723968000000,
"device_id": "2824bb020002249f",
"source": "esp32-ds18b20"
}

7.1 创建 API Token

登录 blog-api 管理后台,创建一个 write 权限的 API Token,或者直接用 curl:

curl -X POST https://your-api-domain.com/api/v1/admin/api-tokens \
-H "Authorization: Bearer <你的JWT>" \
-H "Content-Type: application/json" \
-d '{"name":"ESP32温度上传","permissions":"write"}'

把返回的 sk_xxx 填到 api_config.py

API_BASE_URL = 'https://your-api-domain.com'
API_TOKEN = 'sk_你的Token'
UPLOAD_INTERVAL_MS = 300000 # 5 分钟

7.2 上传脚本

temp_uploader.py 核心逻辑:

import network
import time
import urequests
import ujson
import ntptime
from machine import Pin
import onewire
import ds18x20
from wifi_config import SSID, PASSWORD
from api_config import API_BASE_URL, API_TOKEN, UPLOAD_INTERVAL_MS

DS_PIN = 13


def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
pass
print('IP:', wlan.ifconfig()[0])


def sync_ntp():
try:
ntptime.settime()
print('NTP synced')
except Exception as e:
print('NTP sync failed:', e)


def read_temperature():
ds_sensor = ds18x20.DS18X20(onewire.OneWire(Pin(DS_PIN)))
roms = ds_sensor.scan()
if not roms:
return None, None
ds_sensor.convert_temp()
time.sleep_ms(750)
rom = roms[0]
temp = ds_sensor.read_temp(rom)
rom_hex = ''.join('{:02x}'.format(b) for b in rom)
return round(temp, 2), rom_hex


def upload_temperature(value, device_id):
url = API_BASE_URL + '/api/v1/temperature/realtime'
headers = {
'Authorization': 'Bearer ' + API_TOKEN,
'Content-Type': 'application/json',
}
# 当前 MicroPython 的 time.time() 使用 2000-01-01 为 epoch,
# 需要加上 1970-01-01 到 2000-01-01 的秒数偏移,转换为标准 Unix 毫秒时间戳
unix_timestamp_ms = (time.time() + 946684800) * 1000
payload = {
'value': value,
'timestamp': unix_timestamp_ms,
'device_id': device_id,
'source': 'esp32-ds18b20',
}
response = urequests.post(url, headers=headers, data=ujson.dumps(payload), timeout=15)
status = response.status_code
response.close()
return 200 <= status < 300


def main():
connect_wifi()
sync_ntp()
while True:
temp, rom = read_temperature()
if temp is not None:
print('Temperature:', temp, '°C')
upload_temperature(temp, rom)
time.sleep_ms(UPLOAD_INTERVAL_MS)


main()

运行后 ESP32 会每 5 分钟读取一次温度并上传到 blog-api 的 realtime_temperature_records 表。

7.3 验证数据

公开查询接口:

# 最新一条
curl "https://your-api-domain.com/api/v1/public/temperature/realtime?user_id=1"

# 最近 7 天历史
curl "https://your-api-domain.com/api/v1/public/temperature/history?user_id=1&days=7"

user_id 换成你的实际用户 ID 即可。

8. 效果展示

数据上传后,我在博客首页加了一个「当前杭州温度」组件,点击温度会弹出最近 1 天和最近 30 天的温度趋势图。下面这张图就是今早刚截的实时效果:

博客首页温度趋势

9. 视频演示

下面是这次折腾过程的视频演示:

B站视频演示
点击进入观看

10. 下一步

可以在博客前端加一个温度卡片,调用 /api/v1/public/temperature/realtime 展示当前环境温度。再加一个折线图调用 /history 展示 24 小时趋势,就是一个完整的无线温度计看板了。

文章作者:阿文
文章链接: https://www.awen.me/post/91d7d138.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿文的博客

评论

0 条评论
😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘 🛑📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭 ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️ 🈯💹❇️ ✳️🌐 💠Ⓜ️🌀 💤🏧🚾 🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️
加载中...

留言反馈

😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘 🛑📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭 ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️ 🈯💹❇️ ✳️🌐 💠Ⓜ️🌀 💤🏧🚾 🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️