✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进

❤欢迎关注我的知乎:对error视而不见

代码获取、问题探讨及文章转载可私信。

☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。

🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇

点击领取更多详细资料

一、DS18B20简介

DS18B20是一款由Dallas Semiconductor公司生产的单总线数字温度传感器。它具有以下特点:

  • 单总线接口:仅需一根数据线即可与微控制器进行通信,大大减少了硬件连接的复杂性。
  • 高精度测量:测量范围为 - 55°C 至 + 125°C,精度可达 ± 0.5°C。
  • 可编程分辨率:可以通过配置寄存器设置9 - 12位的分辨率,对应的温度精度分别为 0.5°C、0.25°C、0.125°C 和 0.0625°C。
  • 自带温度校准:内部集成了温度校准电路,无需额外的校准操作。

二、硬件连接

DS18B20通常有三个引脚:VDD(电源)、GND(接地)和DQ(数据)。连接时,VDD接电源(一般为3.3V或5V),GND接地,DQ引脚连接到微控制器的一个GPIO引脚。为了保证通信的稳定性,通常需要在DQ引脚上拉一个4.7KΩ的电阻到电源。

三、通信协议

DS18B20采用单总线通信协议,通信过程主要包括初始化、ROM操作命令和功能命令三个步骤。

1. 初始化

初始化过程是主机和DS18B20建立通信的第一步。主机通过拉低数据线至少480μs,然后释放数据线,等待15 - 60μs后,检测DS18B20是否存在。如果DS18B20存在,它会拉低数据线60 - 240μs作为响应。

2. ROM操作命令

在初始化成功后,主机可以发送ROM操作命令来识别总线上的DS18B20。常见的ROM操作命令有:

  • 搜索ROM(0xF0):用于识别总线上所有DS18B20的64位ROM代码。
  • 读取ROM(0x33):用于读取单个DS18B20的64位ROM代码。
  • 匹配ROM(0x55):用于指定与主机通信的DS18B20。
  • 跳过ROM(0xCC):当总线上只有一个DS18B20时,可以跳过ROM操作,直接进行功能命令操作。

3. 功能命令

在完成ROM操作后,主机可以发送功能命令来控制DS18B20的工作。常见的功能命令有:

  • 温度转换(0x44):启动DS18B20进行温度转换。
  • 读取暂存器(0xBE):读取DS18B20内部暂存器中的温度数据。

四、代码实现(以STM32为例,使用HAL库)

#include "stm32f1xx_hal.h"
#include <stdio.h>

// 定义DS18B20连接的GPIO引脚
#define DS18B20_PORT GPIOA
#define DS18B20_PIN GPIO_PIN_0

// 初始化DS18B20
uint8_t DS18B20_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    // 使能GPIOA时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 配置DS18B20引脚为推挽输出模式
    GPIO_InitStruct.Pin = DS18B20_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);

    // 拉低数据线至少480μs
    HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
    HAL_Delay(1); // 延时1ms

    // 释放数据线
    HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
    HAL_Delay(1); // 延时1ms

    // 检测DS18B20的响应
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
    if (HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN) == GPIO_PIN_RESET)
    {
        HAL_Delay(2); // 延时2ms
        if (HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN) == GPIO_PIN_SET)
        {
            return 1; // 初始化成功
        }
    }
    return 0; // 初始化失败
}

// 向DS18B20写入一个字节
void DS18B20_WriteByte(uint8_t dat)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);

    for (uint8_t i = 0; i < 8; i++)
    {
        HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
        HAL_Delay(1); // 延时1μs
        if (dat & 0x01)
        {
            HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
        }
        else
        {
            HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
        }
        HAL_Delay(60); // 延时60μs
        HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
        dat >>= 1;
    }
}

// 从DS18B20读取一个字节
uint8_t DS18B20_ReadByte(void)
{
    uint8_t dat = 0;
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);

    for (uint8_t i = 0; i < 8; i++)
    {
        HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
        HAL_Delay(1); // 延时1μs
        HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
        HAL_Delay(1); // 延时1μs
        dat >>= 1;
        if (HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN) == GPIO_PIN_SET)
        {
            dat |= 0x80;
        }
        HAL_Delay(60); // 延时60μs
    }
    return dat;
}

// 启动DS18B20进行温度转换
void DS18B20_StartConvert(void)
{
    if (DS18B20_Init())
    {
        DS18B20_WriteByte(0xCC); // 跳过ROM操作
        DS18B20_WriteByte(0x44); // 启动温度转换
    }
}

// 读取DS18B20的温度值
float DS18B20_ReadTemperature(void)
{
    uint8_t LSB, MSB;
    int16_t temp;
    float temperature;

    if (DS18B20_Init())
    {
        DS18B20_WriteByte(0xCC); // 跳过ROM操作
        DS18B20_WriteByte(0xBE); // 读取暂存器

        LSB = DS18B20_ReadByte();
        MSB = DS18B20_ReadByte();

        temp = (MSB << 8) | LSB;
        temperature = (float)temp / 16.0;
    }
    else
    {
        temperature = -127.0; // 初始化失败,返回错误值
    }
    return temperature;
}

int main(void)
{
    HAL_Init();
    float temperature;

    while (1)
    {
        DS18B20_StartConvert();
        HAL_Delay(750); // 等待温度转换完成
        temperature = DS18B20_ReadTemperature();
        printf("Temperature: %.2f°C\n", temperature);
        HAL_Delay(1000); // 每隔1秒读取一次温度
    }
}

五、代码解释

  1. DS18B20_Init函数:用于初始化DS18B20,通过拉低和释放数据线,检测DS18B20的响应信号,判断初始化是否成功。
  2. DS18B20_WriteByte函数:向DS18B20写入一个字节的数据,通过逐位发送的方式将数据写入。
  3. DS18B20_ReadByte函数:从DS18B20读取一个字节的数据,通过逐位读取的方式将数据读取出来。
  4. DS18B20_StartConvert函数:启动DS18B20进行温度转换,先跳过ROM操作,然后发送温度转换命令。
  5. DS18B20_ReadTemperature函数:读取DS18B20的温度值,先跳过ROM操作,然后发送读取暂存器命令,读取低字节和高字节的数据,将其组合成一个16位的整数,最后转换为浮点数表示的温度值。
  6. main函数:在主函数中,循环调用DS18B20_StartConvert函数启动温度转换,等待750ms(保证温度转换完成),然后调用DS18B20_ReadTemperature函数读取温度值,并通过串口输出。

通过以上步骤和代码,我们可以成功驱动DS18B20温度传感器,实现温度的测量和读取。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐