【CanMV K210】传感器实验 DS18B20 温度读取与环境判断

在智能硬件项目中,温度采集是非常常见的基础能力。机房环境监测、设备散热检测、温控风扇、冷链运输、农业大棚、智能家居,都需要把真实环境中的温度变化转换成程序可以处理的数据。对于 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、摄像头、蜂鸣器、按键、电机等模块,因此这些内容不作为本节重点。软件侧主要使用 timemicropython.constfpioa_manager.fmmodules.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.onewirefpioa_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_LIMITHIGH_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 硬件联动等方向。理解了这套采集流程之后,更多传感器实验都可以沿用同样的工程思路。

相关推荐
陆业聪10 小时前
微调:让通用大模型变成你的「专属定制ROM」——从AOSP到LoRA的迁移学习
人工智能·aigc
wy_hhxx10 小时前
Win11 环境部署 Codex、Claude Code + 国产模型
人工智能
薛定猫AI10 小时前
【深度解析】Antigravity 更新背后的工程化思路:从沙盒权限到长上下文的 AI 编程工具演进
人工智能
qcx2310 小时前
【系统学AI】02 token机制全解:LLM如何‘读懂‘人类语言
人工智能·llm·产品经理·token·费用·deepseek
俊哥V10 小时前
每日 AI 研究简报 · 2026-05-24
人工智能·ai
小糖学代码10 小时前
LLM系列:1.python入门:12.异常处理(Exceptions)
前端·人工智能·python·深度学习
BreezeJiang10 小时前
从零开始,手把手带你搭建一个全栈项目
人工智能
小小测试开发11 小时前
KanBots:开源看板工具,每张卡片跑一个并行 AI Agent,Hacker News 147 星炸裂
人工智能
●VON11 小时前
OpenClaw 架构解析:Skill 与 Agent 的设计哲学与实现机制
人工智能·app·agent·skill·豆包·deepseek