Skip to content

DS18B20温度传感器

简介

SHT30是一款高精度、数字输出、电容式温湿度传感器,具有 excellent 的长期稳定性和可靠性。它采用创新的电容式技术,能够提供高精度的温度和湿度测量结果。SHT30传感器具有以下特点:

  • 高精度:温度和湿度测量精度可达±0.3℃和±2%RH。

引脚定义

引脚名称描述
VDD电源引脚,连接到3.3V或5V电源
GND地线引脚,连接到电路板的地线
DQ数据引脚,用于与微控制器通信

数据手册

DS18B20 数据手册

代码示例

1.ESP-IDF 示例(简单使用)

c
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define DS18B20_PIN GPIO_NUM_1 // 定义DS18B20的GPIO引脚

static const char *TAG = "DS18B20";

// 自定义OneWire协议实现
void ds18b20_delay_us(uint32_t us) {
    esp_rom_delay_us(us); // 使用 ESP-IDF 提供的精确微秒延迟函数
}

bool ds18b20_reset() {
    gpio_set_direction(DS18B20_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(DS18B20_PIN, 0); // 拉低总线
    ds18b20_delay_us(480); // 持续480us
    gpio_set_direction(DS18B20_PIN, GPIO_MODE_INPUT); // 切换为输入模式
    ds18b20_delay_us(60); // 等待60us
    bool presence = gpio_get_level(DS18B20_PIN); // 检测是否存在设备
    ds18b20_delay_us(420); // 等待420us
    return !presence; // 返回是否存在设备
}

void ds18b20_write_bit(bool bit) {
    gpio_set_direction(DS18B20_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(DS18B20_PIN, 0); // 拉低总线
    ds18b20_delay_us(1); // 持续1us
    gpio_set_level(DS18B20_PIN, bit); // 写入数据位
    ds18b20_delay_us(60); // 持续60us
    gpio_set_level(DS18B20_PIN, 1); // 释放总线
    ds18b20_delay_us(1); // 持续1us
}

bool ds18b20_read_bit() {
    gpio_set_direction(DS18B20_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(DS18B20_PIN, 0); // 拉低总线
    ds18b20_delay_us(1); // 持续1us
    gpio_set_direction(DS18B20_PIN, GPIO_MODE_INPUT); // 切换为输入模式
    ds18b20_delay_us(14); // 等待14us
    bool bit = gpio_get_level(DS18B20_PIN); // 读取数据位
    ds18b20_delay_us(45); // 等待45us
    return bit;
}

void ds18b20_write_byte(uint8_t byte) {
    for (int i = 0; i < 8; i++) {
        ds18b20_write_bit((byte >> i) & 0x01); // 从最低位开始写入
    }
}

uint8_t ds18b20_read_byte() {
    uint8_t byte = 0;
    for (int i = 0; i < 8; i++) {
        if (ds18b20_read_bit()) {
            byte |= (1 << i);  // 从最低位开始设置
        }
    }
    return byte;
}

// 初始化DS18B20
void ds18b20_init() {
    // 不需要额外初始化
}

// 添加 CRC8 计算函数
uint8_t onewire_crc8(const uint8_t *data, uint8_t len) {
    uint8_t crc = 0;
    while (len--) {
        uint8_t inbyte = *data++;
        for (uint8_t i = 8; i; i--) {
            uint8_t mix = (crc ^ inbyte) & 0x01;
            crc >>= 1;
            if (mix) crc ^= 0x8C;
            inbyte >>= 1;
        }
    }
    return crc;
}

// 读取DS18B20温度值
float ds18b20_read_temp() {
    uint8_t data[9];
    uint8_t crc;

    // 发送复位信号
    if (!ds18b20_reset()) {
        ESP_LOGE(TAG, "DS18B20 not found!");
        return -127.0;
    }

    // 发送跳过ROM命令
    ds18b20_write_byte(0xCC);
    // 发送转换温度命令
    ds18b20_write_byte(0x44);

    // 等待转换完成
    vTaskDelay(pdMS_TO_TICKS(750));

    // 再次发送复位信号
    if (!ds18b20_reset()) {
        ESP_LOGE(TAG, "DS18B20 not found!");
        return -127.0;
    }

    // 发送跳过ROM命令
    ds18b20_write_byte(0xCC);
    // 发送读取数据命令
    ds18b20_write_byte(0xBE);

    // 读取温度数据
    for (int i = 0; i < 9; i++) {
        data[i] = ds18b20_read_byte();
    }

    // 验证CRC
    crc = onewire_crc8(data, 8);
    if (crc != data[8]) {
        ESP_LOGE(TAG, "CRC error!");
        return -127.0;
    }

    // 计算温度值
    int16_t raw_temp = (data[1] << 8) | data[0];
    float temp = (float)raw_temp / 16.0;

    // 检查符号位
    if (raw_temp & 0x8000) { // 如果最高位为1,表示负数
        temp = -((~raw_temp + 1) / 16.0);
    }

    return temp;
}

void app_main(void) {
    ds18b20_init(); // 初始化DS18B20
    // gpio_set_direction(DS18B20_PIN, GPIO_MODE_OUTPUT);

    while (1) {
        float temp = ds18b20_read_temp(); // 读取温度值
        if (temp != -127.0) {
            ESP_LOGI(TAG, "Temperature: %.2f C", temp); // 打印温度值
        } else {
            ESP_LOGE(TAG, "Failed to read temperature.");
        }


        // gpio_set_level(DS18B20_PIN, 0); // 拉低总线
        // ds18b20_delay_us(480);
        // gpio_set_level(DS18B20_PIN, 1); // 释放总线
        // ds18b20_delay_us(60);

        vTaskDelay(pdMS_TO_TICKS(1000)); // 等待1秒
    }
}

2.ESP-IDF 示例(使用esp-idfonewire组件)

本示例使用 esp-idfds18b20 组件, 当然这个组件也是基于 onewire 组件的。ds18b20 组件提供了更高级的 API,可以更方便地与 DS18B20 温度传感器进行通信。

使用方法:

  1. 添加 ds18b20 组件到 idf.py 文件中。 访问: ds18b20组件 在 终端执行: idf.py add-dependency "espressif/ds18b20^0.1.2"

  2. 然后编写下面的代码:

c
/*
 * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdio.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ds18b20.h"
#include "onewire_bus.h"

#define EXAMPLE_ONEWIRE_BUS_GPIO 1
#define EXAMPLE_ONEWIRE_MAX_DS18B20 2

static const char *TAG = "ds18b20_example";


// Now you have the DS18B20 sensor handle, you can use it to read the temperature

void app_main(void)
{
    float temperature = 0.0f;
   // install 1-wire bus
    onewire_bus_handle_t bus = NULL;
    onewire_bus_config_t bus_config = {
        .bus_gpio_num = EXAMPLE_ONEWIRE_BUS_GPIO,
    };
    onewire_bus_rmt_config_t rmt_config = {
        .max_rx_bytes = 10, // 1byte ROM command + 8byte ROM number + 1byte device command, 对于 DS18B20, 这里设置为10就可以了.
    };
    ESP_ERROR_CHECK(onewire_new_bus_rmt(&bus_config, &rmt_config, &bus));

    int ds18b20_device_num = 0;
    ds18b20_device_handle_t ds18b20s[EXAMPLE_ONEWIRE_MAX_DS18B20];
    onewire_device_iter_handle_t iter = NULL;
    onewire_device_t next_onewire_device;
    esp_err_t search_result = ESP_OK;

    // create 1-wire device iterator, which is used for device search
    ESP_ERROR_CHECK(onewire_new_device_iter(bus, &iter));
    ESP_LOGI(TAG, "Device iterator created, start searching...");
    do
    {
        search_result = onewire_device_iter_get_next(iter, &next_onewire_device);
        if (search_result == ESP_OK)
        { // found a new device, let's check if we can upgrade it to a DS18B20
            ds18b20_config_t ds_cfg = {};
            // check if the device is a DS18B20, if so, return the ds18b20 handle
            if (ds18b20_new_device(&next_onewire_device, &ds_cfg, &ds18b20s[ds18b20_device_num]) == ESP_OK)
            {
                ESP_LOGI(TAG, "Found a DS18B20[%d], address: %016llX", ds18b20_device_num, next_onewire_device.address);
                ds18b20_device_num++;
            }
            else
            {
                ESP_LOGI(TAG, "Found an unknown device, address: %016llX", next_onewire_device.address);
            }
        }
    } while (search_result != ESP_ERR_NOT_FOUND);
    ESP_ERROR_CHECK(onewire_del_device_iter(iter));
    ESP_LOGI(TAG, "Searching done, %d DS18B20 device(s) found", ds18b20_device_num);
    while (1)
    {
        for (int i = 0; i < ds18b20_device_num; i++)
        {
            ESP_ERROR_CHECK(ds18b20_trigger_temperature_conversion(ds18b20s[i]));
            ESP_ERROR_CHECK(ds18b20_get_temperature(ds18b20s[i], &temperature));
            ESP_LOGI(TAG, "temperature read from DS18B20[%d]: %.2fC", i, temperature);
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

3.ESP-IDF 示例2的解析

使用onewire来读取18b20的步骤是什么? 假如只有一个18b20芯片, 那么这个步骤是什么?

使用 OneWire 协议读取 DS18B20 温度传感器(只有一个芯片)的步骤可以分为以下几个阶段:

📌 一、硬件准备
使用一个 DS18B20 温度传感器
连接方式:
VCC 接电源(3.3V 或 5V)
GND 接地
DATA 接 MCU 的 GPIO 引脚,加上一个 4.7kΩ 上拉电阻 到 VCC
可以使用寄生供电模式(即 VCC 接 GND),但推荐正常供电更稳定
📌 二、软件流程概览
1. 初始化 OneWire 总线
2. 搜索设备(如果只有一个设备,可跳过搜索,直接复位后进行操作)
3. 发送 ROM 命令(由于只有一个设备,可以直接跳过 ROM)
4. 启动温度转换
5. 等待转换完成(或轮询是否完成)
6. 再次初始化总线并发送命令读取温度数据
7. 解析数据,得到实际温度值

使用onewire来读取18b20的步骤是什么? 假如有多个18b20芯片都是通过同一个接口连接起来.那么这个步骤是什么?

当你有多个 DS18B20 芯片连接在同一个 OneWire 总线上 时,读取温度的流程与只有一个芯片的情况类似,但需要额外处理设备的地址识别和轮询 。

📌 一、基本原理
多个 DS18B20 是通过 OneWire 总线并联 在一起的
每个 DS18B20 都有一个唯一的 64 位 ROM 地址(出厂烧录)
主机可以通过 MATCH ROM 命令来选择特定的 DS18B20 进行通信
📌 二、整体步骤
✅ 1. 初始化 OneWire 总线
✅ 2. 搜索总线上的所有 DS18B20 设备,保存它们的 ROM 地址
✅ 3. 对每个设备依次:
1. 发送 MATCH ROM 命令 + ROM 地址
2. 启动温度转换
3. 等待转换完成
4. 再次发送 MATCH ROM + ROM 地址
5. 读取温度数据
6. 解析为实际温度值