618|2

101

帖子

1

TA的资源

一粒金砂(高级)

楼主
 

FireBeetle 2 ESP32 C6开发板 DS18B20的驱动的实现与测试 [复制链接]

 
本帖最后由 尹小舟 于 2024-6-4 10:58 编辑

1 . DS18B20

           是Dallas Semiconductor(现在属于Maxim Integrated Products)制造的一种常用的1-Wire接口的数字温度计。

主要特性:

  1. 1-Wire接口:只需一个数据线(加上地线)即可与微控制器通信,简化了硬件设计。
  2. 数字输出:直接输出数字温度值,无需额外的A/D转换电路。
  3. 测量范围:通常为-55°C到+125°C(不同型号可能有所不同)。
  4. 分辨率:可编程为9位到12位,对应于0.5°C到0.0625°C的分辨率。
  5. 多点测温:可以在同一数据线上连接多个DS18B20传感器,通过ROM命令识别每个传感器。
  6. 低功耗:在待机模式下功耗极低,适合电池供电的应用。
  7. 封装:常见封装为TO-92(晶体管封装)或小型表面贴装封装(如SOT-23)。

 

可应用于环境控制、设备或过程控制、消费类测温电子产品等。

 

2 .  DS18B20注意千万不要接反

 

 

DS18B20通常有三根引脚:VCC(电源正极)、GND(地线)和DQ(数字信号线)。在连接时,需要确保:

  1. VCC:连接到微控制器或电源的正极(通常是+5V或+3.3V,取决于你的系统和DS18B20的型号)。
  2. GND:连接到微控制器或电源的负极(地线)。
  3. DQ:连接到微控制器的数据线上。这根线用于与DS18B20进行1-Wire通信。

其他元件,一般VCC和GND不是对称的,接反不会烧毁,DS18B20接反的话会直接短路。

 

        DS18B20的体积很小,用它组成的温度测量系统线路非常简单,只需要一根数据线即可实现通信,并且可通过数据线寄生供电。单总线系统只有一根数据线,主机或从机设备通过一个漏极开路(或3态端口连接至该数据线,从而使得主机或从机设备在不发送数据时可释放数据总线,以便总线可被其他设备使用。由DS18B20的DO开漏等效电路图可知,其单总线要求外接一个约5kΩ的上拉电阻,以保证总线闲置时为高电平。

3 . 内部结构

 

DS18B20的温度测量范围在-55~+125℃之间,数字温度计的分辨率可以从9~12位选择(默认为12位),内部可设置非易失报警温度上、下限(TH、TL),每个器件均有唯一的8字节(64位)光刻码(LaseredROMCode),分别为1字节CRC检验码、6字节序列号和1字节家族代码(FamilyCode:0x28),这使得多个DS18B20传感器可以共用总线构成多点测温网络。利用ROM 搜索命令可通过排除法获取总线上挂载的所有器件的光刻码,利用报警搜索命令可识别并标识出总线上所有超过限定温度的器件。

 

4 . DS18B20 的时序

        之前我使用Arduino的库驱动失败了,要自己实现DS18B20驱动了

        单总线器件要求遵守严格的通信协议以保证数据的完整性,该协议定义了几种信号类型,包括复位脉冲、应答脉冲(在线脉冲或称存在脉冲)、写0/1、读0/1,除了应答脉冲以外,其余信号均由主机发出同步信号,并且发送的所有命令和数据都是字节的低位在前。时序如下图

 

 

5 . delayMicroseconds()

在Arduino 中 delayMicroseconds()与delay()函数都可用于延迟程序运行。不同的是,delayMicroseconds()的参数单位是微秒(1毫秒=1000微秒)。

6.程序代码

#include "Arduino.h"
#include "esp_system.h"

/* 引脚定义 */
#define DS18B20_DQ_PIN      SCL

/* 宏函数 */
#define DS18B20_DQ_OUT(x)   digitalWrite(DS18B20_DQ_PIN, x)
#define DS18B20_DQ_IN       digitalRead(DS18B20_DQ_PIN)

#define DS18B20_MODE_IN     pinMode(DS18B20_DQ_PIN, INPUT)
#define DS18B20_MODE_OUT    pinMode(DS18B20_DQ_PIN, OUTPUT)

/**
 * [url=home.php?mod=space&uid=159083]@brief[/url]       复位DS18B20
 * @param       无
 * @retval      无
 */
static void ds18b20_reset(void)
{
    DS18B20_MODE_OUT;
    DS18B20_DQ_OUT(0);        /* 拉低DQ,复位 */
    delayMicroseconds(750);   /* 拉低750us */
    DS18B20_DQ_OUT(1);        /* DQ=1, 释放复位 */
    delayMicroseconds(15);    /* 延迟15US */
}

/**
 * @brief       等待DS18B20的回应
 * @param       无
 * @retval      0, DS18B20正常
 *              1, DS18B20异常/不存在
 */
uint8_t ds18b20_check(void)
{
 
    uint8_t retry = 0;
    uint8_t rval = 0;

    DS18B20_MODE_IN;
    while (DS18B20_DQ_IN && retry < 200)    /* 等待DQ变低, 等待200us */
    {
        retry++;
        delayMicroseconds(1);
    }

    if (retry >= 240)
    {
        rval = 1;
    }
    else
    {
        retry = 0;

        while (!DS18B20_DQ_IN && retry < 240)   /* 等待DQ变高, 等待240us */
        {
            retry++;
            delayMicroseconds(1);
        }

        if (retry >= 240)
        {
            rval = 1;
        }
    }
    delayMicroseconds(400);
    return rval;
}

/**
 * @brief       从DS18B20读取一个位
 * @param       无
 * @retval      读取到的位值: 0 / 1
 */
static uint8_t ds18b20_read_bit(void)
{
    uint8_t data = 0;

    DS18B20_MODE_OUT;
    DS18B20_DQ_OUT(0);
    delayMicroseconds(2);
    DS18B20_DQ_OUT(1);
    delayMicroseconds(16);

    DS18B20_MODE_IN;
    if (DS18B20_DQ_IN)
    {
        data = 1;
    }

    delayMicroseconds(50);
    return data;
}

/**
 * @brief       从DS18B20读取一个字节
 * @param       无
 * @retval      读到的数据
 */
static uint8_t ds18b20_read_byte(void)
{
    uint8_t i, b, data = 0;

    for (i = 0; i < 8; i++)
    {
        b = ds18b20_read_bit(); /* DS18B20先输出低位数据 ,高位数据后输出 */
        
        data |= b << i;         /* 填充data的每一位 */ 
    }

    return data;
}

/**
 * @brief       写一个字节到DS18B20
 * @param       data: 要写入的字节
 * @retval      无
 */
static void ds18b20_write_byte(uint8_t data)
{
    uint8_t j;

    DS18B20_MODE_OUT;

    for (j = 1; j <= 8; j++)
    {
        if (data & 0x01)
        {
            DS18B20_DQ_OUT(0);  
            delayMicroseconds(2);
            DS18B20_DQ_OUT(1);
            delayMicroseconds(60);
        }
        else
        {
            DS18B20_DQ_OUT(0);  
            delayMicroseconds(60);
            DS18B20_DQ_OUT(1);
            delayMicroseconds(2);
        }

        data >>= 1;             
    }
}

/**
 * @brief       开始温度转换
 * @param       无
 * @retval      无
 */
static void ds18b20_start(void)
{
    ds18b20_reset();
    if(ds18b20_check())
    {
       
        Serial.printf("没有找到DS18B20\r\n");
    }
    
    ds18b20_write_byte(0xcc);   /*  skip rom */
    ds18b20_write_byte(0x44);   /*  convert */
    delayMicroseconds(970);
}

/**
* @brief       初始化DS18B20
* @param       无
* @retval      0:正常,1:不存在/不正常
*/
uint8_t ds18b20_init(void) 
{
    ds18b20_reset();
    return ds18b20_check();
}

/**
 * @brief       从ds18b20得到温度值(精度:0.1C)
 * @param       无
 * @retval      温度值 (-550~1250)
 *   @note      返回的温度值放大了10倍.
 *              实际使用的时候,要除以10才是实际温度.
 */
short ds18b20_get_temperature(void)
{
    uint8_t flag = 1;           /* 默认温度为正数 */
    uint8_t TL = 0, TH = 0;
    short temp;

    ds18b20_start();            /*  ds1820 start convert */
    ds18b20_reset();
    ds18b20_check();
    ds18b20_write_byte(0xcc);   /*  skip rom */
    ds18b20_write_byte(0xbe);   /*  convert */
    TL = ds18b20_read_byte();   /*  LSB */
    TH = ds18b20_read_byte();   /*  MSB */
    Serial.printf("DS18B20 Data  TL = %d  TH = %d\r\n",TL,TH);
    if (TH > 7)
    { /* 温度为负,查看DS18B20的温度表示法与计算机存储正负数据的原理一致:
        正数补码为寄存器存储的数据自身,负数补码为寄存器存储值按位取反后+1
        所以我们直接取它实际的负数部分,但负数的补码为取反后加一,但考虑到低位可能+1后有进位和代码冗余,
        我们这里先暂时没有作+1的处理,这里需要留意	*/
        TH = ~TH;
        TL = ~TL;
        flag = 0;   
    }

    temp = TH;      /* 获得高八位 */
    temp <<= 8;
    temp += TL;     /* 获得底八位 */

    /* 转换成实际温度 */
    if (flag == 0)
    { /* 将温度转换成负温度,这里的+1参考前面的说明 */
        temp = (double)(temp + 1) * 0.625;
        temp = -temp;   
    }
    else
    {
        temp = (double)temp * 0.625;				
    }

    return temp;
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  if(ds18b20_init())
  {
     Serial.printf("没有找到DS18B20\r\n");
  }

}

void loop() {
  short c_data = 0;
  // put your main code here, to run repeatedly:
  c_data = ds18b20_get_temperature();
  Serial.printf("DS18B20 Data = %d\r\n",c_data);
  delay(100);
}

 

 

 

最新回复

官方有库可以下载吗?  详情 回复 发表于 2024-6-6 17:13
点赞 关注
 
 

回复
举报

6841

帖子

11

TA的资源

版主

沙发
 

单总线,速度怎么样,如果挂在多个器件,ROM的ID有什么好方法吗?

 
 
 

回复

222

帖子

3

TA的资源

一粒金砂(高级)

板凳
 

官方有库可以下载吗?


 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表