Other

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

一个不阻塞的 DS18B20 驱动,为什么值得你重写自己的代码?

项目背景与痛点

如果你在 STM32 上写过 DS18B20 的驱动,大概率经历过这样的场景:while 循环死等某个电平翻转,CPU 被一个温度传感器彻底绑架。DS18B20 走的是单总线(1-Wire)协议,时序要求在微秒级,稍有不慎就会采样失败。传统写法几乎无一例外地采用阻塞式延时,要么用 HAL_Delay() 死等,要么自己写空循环数拍子。

在裸机系统上这还能忍,一旦你上了 RTOS,或者需要同时驱动多个 DS18B20 挂在同一根总线上(这本是单总线协议的最大卖点),问题就爆发了。更麻烦的是,DS18B20 的温度转换时间最长需要 750ms,这段时间内整个主循环都被迫停顿。当你尝试把多路传感器放到同一个总线上时,代码复杂度呈指数级上升。

这个库存在的意义就是:把单总线的时序、状态机和多设备管理全部封装好,让你在调用 API 时完全不用关心底层时序细节。

核心技术揭秘

这个库的核心设计是 非阻塞状态机。

所有操作——复位、ROM 搜索、温度转换、读 Scratchpad——都被拆解成有限状态机的迁移步骤。每次 update() 调用只执行一个状态节点,然后立即返回。状态机内部的转移条件由两个维度驱动:当前状态 和 当前时间,而不是等待某个电平或延时结束。

这里有一个必须直面的技术细节:单总线的时序不容妥协。你是非阻塞了,但硬件时序怎么办?答案是 硬件层依然使用阻塞方式处理微秒级时序——状态机处理的是毫秒级事件(比如等待转换完成的 750ms),而微秒级的电平操作仍然用循环或定时器实现。换言之,它是把“长时间等待”换成不阻塞,而不是把“微秒级时序”全部变成异步。这正是本库的高明之处——不装深沉,用回调机制和状态机把等待转换的 750ms 全部归还给调度器。

另外值得关注的是它对 DMA 的支持。很多项目在读取多个传感器时会遇到 CPU 抢占 DMA 的问题,这个库提供了专门的 DMA 兼容路径,算是生产级考量的加分项。

功能亮点与差异

同类竞品,如常见的 OneWire 库(AVR 版移植)、某些阻塞式 STM32 驱动,大多停留在命令封装层面。本库的杀手锏我认为有三点:

第一,单总线上多设备管理的完整实现。 ROM 搜索和匹配不是玩具级别,它能处理超过 5 个传感器挂载的场景——这在同类库里相当少见(很多库只能处理单设备或靠手动设置 ROM 地址)。

第二,非阻塞设计不是堆在驱动层,而是贯穿了整个 API 层级。 GetTemperature 调用后立刻返回,结果靠回调函数后续给你。这对 RTOS 场景简直就是救星——你可以把温度采集当作一次消息发送,而不是占用一个任务线程去死等。

第三,内存占用控制得极好。 全部代码无需动态内存分配,状态存储限定在结构体内部,这在缺乏 MMU 的 STM32 环境中非常重要,也更符合 MISRA 风格的嵌入式 C 逻辑。

值得注意的一点是,该库允许用户主动提供 时间基准源 —— 可以驱动自带的 tick 计数器,也可以手动调用 ms 模拟,这使得它可以适配 HAL 库和裸机寄存器两种开发路径。

应用场景与落地建议

  • 高并发温度采集系统:多路传感器挂在同一总线,每 1 秒轮询一次,所有通信均不阻塞。典型场景是环境监测物联网节点。
  • 需要深度睡眠的电池供电设备:阻塞驱动会让 CPU 在转换期间被迫醒来浪费时间。非阻塞模式配合 WFI 指令可以实现超低功耗采集。
  • 复杂人机交互系统:UI 驱动和采集任务同时跑时,阻塞会让界面卡顿,本库可以平滑化解冲突。

落地注意事项:由于非阻塞状态机本身需要你持续调用 update();如果你把它放在一个优先级特别低的任务里,会导致温度数据刷新不及时。建议给它一个中等级别、固定周期(每 5-10ms)的定时驱动。另外,上电后第一帧读取前需要至少 1 秒的稳定期,这是 DS18B20 本身的上电要求,不是库的缺陷。

综合评价

这个库的价值在于 它把数据手册中的时序页直接变成了工程代码,并且没有牺牲封装性和易用性。它适合那些需要认真对待系统实时性、又不想把时间浪费在单总线调试上的嵌入式团队。

不足方面,我认为有两处:第一,代码中状态的隐式引用较多,阅读源码时新手可能会跟不上逻辑;第二,配置项较多而文档相对精简,实际集成时可能需要阅读 DS18B20_proc.h 头文件才能完整理解初始化流程。如果你追求 out-of-box 的体验,初期需要一点耐心。

瑕不掩瑜,这是目前 STM32 生态里最有潜力成为工业级标准的 DS18B20 驱动库之一。

关于

GitHub 原始描述(英文)

Non-Blocking DS18B20 Library for STM32

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
284
价值分
123
活跃状态
活跃

语言占比

C

Release

贡献者

README

🌡️ DS18B20 Temperature Sensor Library for STM32

A lightweight and non-blocking DS18B20 driver written in C for STM32 (HAL-based).

Built on top of the non-blocking 1-Wire library, it allows reading temperature from one or multiple DS18B20 devices without blocking the CPU.

It supports:

  • 🌡️ DS18B20 – 9–12 bit temperature sensor (Celsius & Fahrenheit)

The library is designed for:

  • Applications requiring non-blocking temperature acquisition
  • Multi-device support on a single 1-Wire bus
  • STM32 projects across All families

✨ Features

  • 🔹 Non-blocking operation using timer callbacks
  • 🔹 Supports multiple DS18B20 devices (OW_MAX_DEVICE)
  • 🔹 Configurable resolution (9–12 bit)
  • 🔹 Temperature read in Celsius and Fahrenheit
  • 🔹 Alarm threshold configuration
  • 🔹 Works with any GPIO pins
  • 🔹 Built on top of HAL-compatible 1-Wire library

⚙️ Installation

1. Copy files directly

Add these files to your STM32 project:

Not yet available; include files manually for now.


🔧 Configuration (ds18b20_config_t)

Set conversion resolution and alarm thresholds (Not yet available):

ds18b20_config_t ds18_conf = {
    .alarm_high = 50,           // High temperature alarm
    .alarm_low  = -50,          // Low temperature alarm
    .cnv_bit    = DS18B20_CNV_BIT_12  // Resolution (9–12 bit)
};

🛠 CubeMX Setup

Read in One-Wire Reopository

🚀 Quick Start

Include header

#include "ds18b20.h"

Define a handle

ds18b20_t ds18;

Timer callback

void ds18_tim_cb(TIM_HandleTypeDef *htim)
{
    ow_callback(&ds18.ow);
}

Optional done callback

void ds18_done_cb(ow_err_t error)
{
}

Initialize DS18B20 in main.c

ow_init_t ow_init_struct;
ow_init_struct.tim_handle = &htim1;
ow_init_struct.gpio = GPIOC;
ow_init_struct.pin = GPIO_PIN_8;
ow_init_struct.tim_cb = ds18_tim_cb;
ow_init_struct.done_cb = NULL;   // Optional
ow_init_struct.rom_id_filter = DS18B20_ID;

ds18b20_init(&ds18, &ow_init_struct);

// Update ROM IDs for all devices
ds18b20_update_rom_id(&ds18);
while(ds18b20_is_busy(&ds18));

// Configure alarm thresholds and resolution
ds18b20_config_t ds18_conf = {
    .alarm_high = 50,
    .alarm_low = -50,
    .cnv_bit = DS18B20_CNV_BIT_12
};
ds18b20_conf(&ds18, &ds18_conf);
while(ds18b20_is_busy(&ds18));

Read temperatures

int16_t temp_c[2];

while(1) {
    ds18b20_cnv(&ds18);
    while(ds18b20_is_busy(&ds18));
    while(!ds18b20_is_cnv_done(&ds18));

    ds18b20_req_read(&ds18, 0);
    while(ds18b20_is_busy(&ds18));
    temp_c[0] = ds18b20_read_c(&ds18);

    ds18b20_req_read(&ds18, 1);
    while(ds18b20_is_busy(&ds18));
    temp_c[1] = ds18b20_read_c(&ds18);
}

🧰 API Overview

Function Description
ds18b20_init() Initialize DS18B20 driver handle
ds18b20_is_busy() Check if bus is busy
ds18b20_last_error() Get last error
ds18b20_update_rom_id() Update connected ROM IDs
ds18b20_cnv() Start temperature conversion
ds18b20_conf() Set configuration (alarm/resolution)
ds18b20_is_cnv_done() Check if conversion is done
ds18b20_req_read() Request temperature read
ds18b20_read_c() Read temperature in Celsius
ds18b20_read_f() Convert Celsius to Fahrenheit

💖 Support

If you find this project useful, please ⭐ star the repo and support!

  • GitHub
  • YouTube
  • Instagram
  • LinkedIn
  • Email
  • Ko-fi

📜 License

Licensed under the terms in the LICENSE.


评论

暂无评论