在智能硬件项目中,温度采集是非常常见的基础能力。机房环境监测、设备散热检测、温控风扇、冷链运输、农业大棚、智能家居,都需要把真实环境中的温度变化转换成程序可以处理的数据。对于 Python 硬件编程入门来说,温度传感器实验比单纯打印变量更直观,因为代码读取的不再是固定数字,而是来自真实环境的实时温度。
本实验使用 CanMV K210 开发板连接 DS18B20 数字温度传感器,通过单总线方式读取温度数据。程序会扫描传感器设备,周期性读取环境温度,并根据阈值判断当前温度处于"偏低""正常"还是"偏高"状态。当温度变化达到设定范围时,串口会输出明显变化提醒;如果传感器未连接或读取失败,程序也会输出对应的异常提示。
| 学习目标 | 说明 |
|---|---|
| 理解温度采集流程 | 认识温度传感器、单总线通信和程序读取之间的关系 |
| 掌握 DS18B20 基础用法 | 使用 DS18B20 读取环境温度,并转换为摄氏温度 |
| 理解单总线通信 | 通过一根 DATA 数据线完成设备搜索、命令发送和数据读取 |
| 学会状态判断 | 根据温度阈值判断偏低、正常和偏高状态 |
| 建立异常处理思路 | 在传感器未连接、读取失败、CRC 校验异常时输出提示 |
| 扩展温控项目能力 | 为 LCD 温度显示、蜂鸣器报警、数据记录和物联网上传打基础 |
这段代码的价值不只是完成一次温度读取,而是展示了一个完整的硬件采集流程:引脚映射、单总线通信、传感器扫描、温度转换、数据校验、状态判断、异常处理和循环采样。这样的结构很接近真实项目中的传感器采集模块,后续可以自然扩展到温度监控系统、数据记录器、报警提示或物联网数据上传。
文章目录
理论基础
DS18B20 是常见的数字温度传感器。和模拟温度传感器不同,DS18B20 不需要外部 ADC 模块转换电压,而是通过内部电路完成温度采集和数据转换,然后通过单总线接口把数字温度数据返回给主控板。开发板读取到的不是简单高低电平,而是一组经过传感器编码的数据,需要按照 DS18B20 的通信流程进行解析。
单总线通信的特点是数据线数量少。DS18B20 的 DATA 引脚既负责接收主控发送的命令,也负责返回传感器数据。程序启动后会先搜索单总线上的设备,找到设备 ROM 后,再发送温度转换命令。转换完成后,程序读取传感器暂存器,通过低字节和高字节组合出温度原始值,最后换算成摄氏温度。
本实验把 DS18B20 的 DATA 连接到 CanMV IO6,并将 IO6 映射为 GPIOHS2。程序使用 modules.onewire 创建单总线通信对象,再通过 scan()、convert_temp()、read_scratch() 和 read_temp() 完成设备扫描、温度转换、暂存器读取和温度计算。整个过程体现的是"真实环境温度 -> 传感器数字数据 -> Python 状态判断"的采集链路。
环境温度变化
空气 / 设备外壳 / 测温点
DS18B20 温度传感器
内部完成温度转换
DATA 单总线
命令发送与数据返回共用一根线
CanMV K210
IO6 映射为 GPIOHS2
onewire 通信
搜索设备 / 读取暂存器 / CRC 校验
温度计算
原始数据转摄氏温度
状态判断
偏低 / 正常 / 偏高
串口输出
温度值 / 变化幅度 / 设备提示
VCC 供电
GND 共地
这张流程图展示的是 DS18B20 温度采集的完整链路。温度变化先被 DS18B20 感知,传感器内部完成转换后,通过 DATA 单总线把数据返回给 CanMV K210。程序读取暂存器数据后进行 CRC 校验和温度换算,再根据阈值输出当前温度状态。
DS18B20 实验中需要注意两个时间点。一个是设备扫描,只有扫描到传感器 ROM 后,后续读取才有对象;另一个是温度转换等待,DS18B20 启动转换后需要一定时间完成测量。代码中设置 CONVERT_DELAY_MS = 750,就是为了给传感器留出转换时间,避免刚发送转换命令就立即读取导致数据不稳定。
硬件设施
本实验围绕 DS18B20 数字温度传感器展开。代码中没有使用 LCD、摄像头、蜂鸣器、按键、电机等模块,因此这些内容不作为本节重点。软件侧主要使用 time、micropython.const、fpioa_manager.fm 和 modules.onewire,它们分别负责延时控制、常量定义、引脚功能映射和单总线通信。
接线关系可以先通过下面这张图建立整体印象。DS18B20 的 VCC 接开发板电源,GND 接开发板地线,DATA 接 CanMV IO6。程序会把 IO6 注册为 GPIOHS2,再通过单总线对象完成温度读取。

| 硬件 / 软件 | 作用 | 说明 |
|---|---|---|
| CanMV K210 开发板 | 实验运行平台 | 负责执行 MicroPython 程序,并通过指定引脚与 DS18B20 通信 |
| DS18B20 数字温度传感器 | 温度采集模块 | 通过单总线方式输出温度数据,一个 DATA 引脚即可完成通信 |
| CanMV IO6 | 数据通信引脚 | 代码中通过 DS18B20_PIN = 6 指定 DS18B20 的 DATA 连接到 IO6 |
| 3.3V / 5V 电源 | 传感器供电 | DS18B20 的 VCC 接开发板电源,具体电压根据模块规格选择 |
| GND | 公共地 | DS18B20 与开发板必须共地,保证通信电平有统一参考 |
fpioa_manager.fm |
引脚功能映射模块 | 将物理引脚 IO6 注册为 GPIOHS2 功能 |
modules.onewire |
单总线通信模块 | 负责 DS18B20 的设备搜索、读写字节、CRC 校验等底层通信 |
time |
延时控制模块 | 控制温度转换等待时间和周期读取间隔 |
micropython.const |
常量定义模块 | 用于定义 DS18B20 通信命令,减少魔法数字带来的阅读成本 |
实验中用到的 DS18B20 模块如下。常见模块会把 VCC、GND、DATA 三个引脚引出,部分模块已经集成 DATA 上拉电阻。如果使用的是裸 DS18B20 器件,DATA 线通常需要外接上拉电阻;如果使用的是教学模块,一般按模块丝印连接即可。

接线关系可以直接从代码注释和硬件配置常量中确认。DS18B20_PIN = 6 表示传感器 DATA 引脚连接到 CanMV IO6,DS18B20_GPIO = fm.fpioa.GPIOHS2 表示程序会把 IO6 映射为高速 GPIO 功能 GPIOHS2。传感器的 VCC 和 GND 分别接开发板电源和地线,DATA 线负责完成温度读取通信。
| DS18B20 引脚 | CanMV 连接 | 代码配置 | 对应功能 | 说明 |
|---|---|---|---|---|
| VCC | 3.3V / 5V | 代码未直接控制 | 传感器供电 | 根据 DS18B20 模块规格选择合适电源 |
| GND | GND | 代码未直接控制 | 公共地 | 与开发板共地,保证通信稳定 |
| DATA | IO6 | DS18B20_PIN = 6 |
单总线数据通信 | IO6 被注册为 GPIOHS2 后用于温度读取 |
| IO6 功能映射 | GPIOHS2 | fm.register(DS18B20_PIN, DS18B20_GPIO, force=True) |
引脚功能注册 | 将物理引脚 IO6 绑定到 DS18B20 通信用的 GPIOHS2 |
| DATA 上拉 | 模块内置或外接 | 代码未直接控制 | 单总线稳定通信 | 裸传感器需要注意 DATA 上拉,模块版通常已处理 |
完成接线后的整体状态如下。检查时重点关注 VCC、GND 和 DATA 三条线:供电是否正常,地线是否共地,DATA 是否确实接到 IO6。程序运行后,串口会显示是否扫描到 DS18B20,扫描成功后会周期性输出温度值和状态判断。

| 实验现象 | 正常表现 | 异常提示 |
|---|---|---|
| 程序启动 | 串口输出 DS18B20 实验启动提示 | 没有输出时检查程序运行和串口连接 |
| 扫描传感器 | 串口显示检测到 DS18B20 数量 | 未检测到时检查 DATA、VCC、GND 和 IO6 映射 |
| 正常读取 | 每隔约 1 秒输出当前温度 | 温度读取失败时检查单总线通信稳定性 |
| 温度变化 | 串口显示变化幅度和状态提示 | 变化过于频繁时调整 CHANGE_LIMIT |
| 温度偏低 | 串口提示当前环境温度较低 | 可根据实际场景调整 LOW_TEMP_LIMIT |
| 温度偏高 | 串口提示当前环境温度较高 | 可根据实际场景调整 HIGH_TEMP_LIMIT |
软件代码
本实验代码围绕 DS18B20 的单总线温度读取展开。程序先定义传感器通信命令和硬件参数,再封装 DS18X20 驱动类处理扫描、转换、暂存器读取和温度计算。温度读取完成后,程序会根据阈值判断状态,并在主循环中持续输出温度信息、变化幅度和异常提示。
| 软件环境 | 作用 | 检查重点 |
|---|---|---|
| CanMV IDE | 编辑、运行和调试 K210 程序 | 能识别开发板串口,并能正常运行基础测试程序 |
| CanMV 固件 | 提供 modules.onewire、fpioa_manager 等模块 |
固件环境需要支持当前单总线和 FPIOA 写法 |
| USB 串口驱动 | 让电脑识别开发板串口 | 串口工具或 IDE 中能看到对应端口 |
| 串口终端 | 查看温度采集结果 | 能看到温度值、状态判断和异常提示 |
| DS18B20 模块 | 数字温度采集 | DATA 接 IO6,VCC 与 GND 连接正确 |
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CanMV K210 DS18B20 数字温度传感器实验 Demo
实验功能:
1. 扫描 DS18B20 温度传感器
2. 周期性读取环境温度
3. 判断温度状态:偏低、正常、偏高
4. 温度变化明显时输出提醒
5. 读取失败时进行异常提示
接线参考:
DS18B20 VCC -> 3.3V / 5V
DS18B20 GND -> GND
DS18B20 DATA -> CanMV IO6
说明:
DS18B20 使用单总线通信方式,一个数据引脚即可完成温度读取。
"""
import time
from micropython import const
from fpioa_manager import fm
from modules import onewire
# =========================
# DS18B20 通信命令
# =========================
_CONVERT = const(0x44) # 启动温度转换
_RD_SCRATCH = const(0xBE) # 读取暂存器
_WR_SCRATCH = const(0x4E) # 写入暂存器
_SKIP_ROM = const(0xCC) # 跳过 ROM,适合单个传感器场景
# =========================
# 硬件配置
# =========================
DS18B20_PIN = 6
DS18B20_GPIO = fm.fpioa.GPIOHS2
READ_INTERVAL_MS = 1000 # 温度读取间隔
CONVERT_DELAY_MS = 750 # DS18B20 12 位精度转换最长约 750ms
LOW_TEMP_LIMIT = 18.0 # 偏低温度阈值
HIGH_TEMP_LIMIT = 30.0 # 偏高温度阈值
CHANGE_LIMIT = 1.0 # 温度变化提醒阈值
# =========================
# DS18B20 驱动类
# =========================
class DS18X20:
def __init__(self, pin):
self.device = onewire(pin)
self.buf = bytearray(9)
def scan(self):
"""
扫描单总线上的 DS18B20 设备
"""
return self.device.search(65)
def convert_temp(self):
"""
启动温度转换
"""
self.device.reset()
self.device.writebyte(_SKIP_ROM)
self.device.writebyte(_CONVERT)
def read_scratch(self, rom):
"""
读取传感器暂存器数据
"""
self.device.reset()
self.device.select(rom)
self.device.writebyte(_RD_SCRATCH)
self.buf = self.device.readbuffer(len(self.buf))
if self.device.crc8(self.buf):
raise Exception("CRC error")
return self.buf
def read_temp(self, roms):
"""
读取温度数据
支持单个或多个 DS18B20
"""
if not roms:
return None
self.convert_temp()
time.sleep_ms(CONVERT_DELAY_MS)
temp_list = []
for rom in roms:
buf = self.read_scratch(rom)
if rom[0] == 0x10:
# DS18S20 兼容处理
if buf[1]:
t = buf[0] >> 1 | 0x80
t = -((~t + 1) & 0xFF)
else:
t = buf[0] >> 1
temperature = t - 0.25 + (buf[7] - buf[6]) / buf[7]
else:
# DS18B20 温度计算
t = buf[1] << 8 | buf[0]
if t & 0x8000:
t = -((t ^ 0xFFFF) + 1)
temperature = t / 16.0
temp_list.append(temperature)
if len(temp_list) == 1:
return temp_list[0]
return tuple(temp_list)
# =========================
# 温度状态判断
# =========================
def get_temp_status(temp):
"""
根据温度返回状态文本
"""
if temp < LOW_TEMP_LIMIT:
return "偏低"
if temp > HIGH_TEMP_LIMIT:
return "偏高"
return "正常"
def print_temp_info(temp, last_temp=None):
"""
输出温度信息
"""
status = get_temp_status(temp)
print("------------------------------")
print("当前温度:{:.2f} ℃".format(temp))
print("温度状态:{}".format(status))
if last_temp is not None:
diff = temp - last_temp
if abs(diff) >= CHANGE_LIMIT:
print("温度变化:{:+.2f} ℃,变化明显".format(diff))
else:
print("温度变化:{:+.2f} ℃,变化平稳".format(diff))
if status == "偏低":
print("设备提示:当前环境温度较低")
elif status == "偏高":
print("设备提示:当前环境温度较高")
else:
print("设备提示:温度处于正常范围")
# =========================
# 初始化
# =========================
def setup():
"""
初始化 DS18B20
"""
fm.register(DS18B20_PIN, DS18B20_GPIO, force=True)
sensor = DS18X20(DS18B20_GPIO)
roms = sensor.scan()
print("DS18B20 温度传感器实验启动")
if not roms:
print("未检测到 DS18B20,请检查接线")
else:
print("检测到 DS18B20 数量:{}".format(len(roms)))
return sensor, roms
# =========================
# 主循环
# =========================
def loop():
sensor, roms = setup()
last_temp = None
while True:
if not roms:
print("等待传感器连接...")
time.sleep_ms(READ_INTERVAL_MS)
roms = sensor.scan()
continue
try:
temp = sensor.read_temp(roms)
if isinstance(temp, tuple):
print("------------------------------")
for index, value in enumerate(temp):
print("传感器{} 温度:{:.2f} ℃".format(index + 1, value))
else:
print_temp_info(temp, last_temp)
last_temp = temp
except Exception as error:
print("温度读取失败:{}".format(error))
time.sleep_ms(READ_INTERVAL_MS)
# =========================
# 程序入口
# =========================
if __name__ == '__main__':
try:
loop()
except KeyboardInterrupt:
print("程序已停止")
这段程序可以分成通信命令定义、硬件参数配置、DS18B20 驱动类、温度状态判断和主循环采样几个部分。通信命令区域使用 const() 定义 _CONVERT、_RD_SCRATCH、_WR_SCRATCH 和 _SKIP_ROM,让代码含义更清晰;硬件配置区域集中保存 DATA 引脚、读取间隔、转换等待时间和温度阈值,便于后续调试。
DS18X20 类封装了传感器驱动逻辑。scan() 用于搜索总线上的 DS18B20 设备,convert_temp() 用于发送温度转换命令,read_scratch() 用于读取传感器暂存器并进行 CRC 校验,read_temp() 负责把暂存器中的原始数据换算成摄氏温度。这样主循环只需要调用 sensor.read_temp(roms),不需要反复编写单总线读写细节。
| 函数名 | 功能 | 对应现象 |
|---|---|---|
DS18X20.__init__() |
创建单总线设备对象和缓存区 | 程序具备与 DS18B20 通信的基础对象 |
scan() |
扫描单总线设备 | 串口输出是否检测到 DS18B20 以及检测数量 |
convert_temp() |
启动温度转换 | 传感器开始把环境温度转换成内部数据 |
read_scratch(rom) |
读取暂存器并校验数据 | 获取传感器原始数据,CRC 异常时抛出错误 |
read_temp(roms) |
读取并计算温度 | 串口得到摄氏温度,支持单个或多个传感器 |
get_temp_status(temp) |
判断温度状态 | 输出"偏低""正常""偏高" |
print_temp_info(temp, last_temp) |
打印温度与变化信息 | 串口显示当前温度、状态、变化幅度和设备提示 |
setup() |
初始化引脚并扫描传感器 | 程序启动后显示实验启动和传感器检测结果 |
loop() |
周期性读取温度 | 每隔 1 秒读取温度,异常时输出失败原因 |
温度计算是本实验的数据处理核心。DS18B20 返回的不是直接可读的浮点温度,而是由低字节和高字节组成的原始数据。代码通过 buf[1] << 8 | buf[0] 合成温度原始值,再判断符号位处理负温度,常规 DS18B20 按 t / 16.0 得到摄氏温度。代码中还保留了 DS18S20 兼容处理,当 ROM 首字节为 0x10 时,会使用另一套计算方式。
loop() 内部先调用 setup() 完成初始化,再进入持续读取流程。如果没有扫描到传感器,程序不会直接退出,而是每隔一段时间重新扫描。这样的写法适合硬件调试场景,传感器临时接触不良或后续重新插入时,程序仍然有机会恢复读取。
扩展应用
DS18B20 实验常见问题集中在供电、DATA 接线、引脚映射、单总线通信和温度转换等待时间上。排查时可以先观察串口输出,如果一直提示未检测到设备,重点检查接线和引脚;如果能够检测到设备但读取失败,重点检查通信稳定性和 CRC 校验。
| 问题现象 | 可能原因 | 处理思路 |
|---|---|---|
| 串口提示未检测到 DS18B20 | DATA 未接 IO6、VCC/GND 接线错误、传感器未供电 | 按照 VCC、GND、DATA 三线重新核对,确认 DATA 接到 CanMV IO6 |
| 一直显示等待传感器连接 | 初始扫描失败,后续扫描仍未找到设备 | 检查 DS18B20_PIN = 6 是否与实际接线一致,必要时重新插拔传感器 |
| 温度读取失败并提示 CRC error | 单总线通信不稳定、接触不良、数据干扰 | 检查杜邦线连接,缩短 DATA 线距离,确认传感器模块接线牢固 |
| 温度数值明显不合理 | 传感器供电异常、读取时机不稳定、模块损坏 | 确认供电电压符合模块要求,保留 CONVERT_DELAY_MS = 750 的转换等待时间 |
| 温度状态判断不符合实际 | 阈值不适合当前环境 | 根据应用场景调整 LOW_TEMP_LIMIT 和 HIGH_TEMP_LIMIT |
| 温度变化提醒过于频繁 | CHANGE_LIMIT 设置太小 |
适当增大变化阈值,例如从 1.0 调整到 2.0 |
| 多个传感器显示为多行数据 | 单总线上扫描到多个设备 | 当前代码支持多个 ROM 读取,会按传感器序号分别输出温度 |
| 裸传感器无法稳定读取 | DATA 线缺少上拉,或连线过长 | 检查是否需要外接上拉电阻,尽量缩短 DATA 线 |
| 串口输出间隔较慢 | 温度转换等待时间和读取间隔叠加 | 这是保证转换稳定的设计,追求更快响应时需要重新权衡精度和稳定性 |
DS18B20 温度读取实验的扩展价值非常高,因为它已经具备了真实项目中传感器采集模块的基础形态。程序不是简单读一次温度,而是包含设备扫描、周期采样、异常处理、状态判断和变化提醒。只要把串口输出替换成屏幕显示、日志记录、网络上传或报警动作,这段代码就可以继续演变成更完整的温度监控应用。
| 应用场景 | 实现思路 | 可扩展能力 |
|---|---|---|
| 室内环境温度监测 | 周期性读取 DS18B20 温度,并在串口输出当前状态 | 后续可扩展 LCD 显示,让温度直接显示在屏幕上 |
| 设备散热检测 | 将 DS18B20 固定在设备外壳或散热区域,监控温度变化 | 可结合阈值判断实现过热提醒 |
| 机房或实验室巡检 | 使用温度状态判断偏低、正常、偏高 | 可扩展数据记录功能,形成温度变化日志 |
| 冷链温度提示 | 根据温度阈值判断环境是否超出设定范围 | 后续可加入蜂鸣器或 LED,实现声光提示 |
| 农业大棚监测 | 读取环境温度并判断是否处于适宜范围 | 可扩展多点传感器采集,形成区域温度对比 |
| 教学演示实验 | 通过温度变化观察传感器采样、阈值判断和异常处理 | 适合讲解单总线通信、数据转换和状态判断 |
| 物联网数据采集 | 将温度值作为设备状态数据 | 后续可扩展 Wi-Fi 或串口上传到服务器 |
| 多点温度采集 | 在同一单总线上接入多个 DS18B20 | 可用于设备不同位置或多个区域的温度对比 |
从工程结构看,当前程序已经把底层传感器通信和上层状态判断拆开。DS18X20 类负责扫描和读取,get_temp_status() 负责业务判断,print_temp_info() 负责输出展示,loop() 负责循环调度。这样的拆分方式方便后续替换输出方式,例如把串口打印改成 LCD 显示、把状态提示改成蜂鸣器报警、把温度数据上传到 Web 服务,而底层温度读取代码不需要大幅改动。
总结
本实验通过 CanMV K210 开发板完成了 DS18B20 数字温度传感器读取,核心能力包括 FPIOA 引脚映射、GPIOHS 单总线通信、传感器扫描、温度转换、暂存器读取、CRC 校验、阈值判断、变化检测和异常处理。代码从硬件接线出发,把 IO6 映射为 GPIOHS2,再通过 onewire 与 DS18B20 通信,读取到原始数据后转换成摄氏温度,并输出更容易理解的状态提示。
这类实验非常适合作为传感器课程的入门案例。温度数据来自真实环境,阈值判断对应实际业务规则,异常处理对应硬件调试场景。后续课程可以继续扩展 LCD 显示、蜂鸣器报警、LED 状态灯、按键切换阈值、多传感器采集、数据保存、网络上传和 AI 硬件联动等方向。理解了这套采集流程之后,更多传感器实验都可以沿用同样的工程思路。