ESP8266接温度传感器18B20时序校准

陈拓 [email protected] 2020/06/22-2020/06/25

 

1. 概述

在《ESP8266_SDK发送温度数据到阿里云》

https://blog.csdn.net/chentuo2000/article/details/105592791

https://zhuanlan.zhihu.com/p/132582024

一文中我们将温度传感器DS18B20的温度数据传送到了阿里云物联网平台。

最近由于受疫情和国际局势的影响,美信原厂的DS18B20涨价了。于是在网上买了几种其他厂商的产品做测试,有些样品读取数据正常,有些不正常,这是因为不同产品的时序有差异,对读取不正常的产品要进行时序校准。

为了时序准确,在《ESP8266毫秒微秒延时测量》一文中

https://zhuanlan.zhihu.com/p/150070320

https://blog.csdn.net/chentuo2000/article/details/106914301

我们首先对ESP8266的延时精度进行了测量。

2. 操作18B20的代码

  • ds18b20.c的头文件ds18b20.h
#ifndef __DS18B20_H__
#define __DS18B20_H__
 
#define DSPORT GPIO_ID_PIN(2) //(DS18B20连接ESP8266-01的GPIO2)
 
uint8_t ds18b20_reset(void);
int ds18b20_read_temp(void);
 
#endif
  • 读18B20的c程序代码ds18b20.c

这是用我新买的18B20校正过的程序。

#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "mem.h"
#include "user_interface.h"
#include "gpio.h"
#include "ds18b20.h"

void delay_1ms(uint16 y) {
    os_delay_us(y * 1000);
}

/* DS18B20复位 */
uint8_t ICACHE_FLASH_ATTR ds18b20_reset(void) {
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO2); // ESP8266-01的GPIO2连接DS18B20的数据线
    GPIO_OUTPUT_SET(DSPORT, 0);     // 将总线拉低480us-960us ,总线上所有器件都将被复位
    os_delay_us(495);               // 保持低电平,使得MASTER Tx > 480us
    GPIO_OUTPUT_SET(DSPORT, 1);     // 拉高电平,释放总线,如果DS18B20做出反应将在15us~60us后拉低总线
    os_delay_us(80);                // 等待DS18B20拉低总线
    uint8_t ack = GPIO_INPUT_GET(DSPORT);   // 获取总线状态
    os_delay_us(380);               // 调节MASTER TR > 480us

    return(ack);                    // 成功返回0,失败返回1
}

/* 写一位数据 */
void ICACHE_FLASH_ATTR write_bit(uint8_t bit) {
    if (bit) {
        GPIO_OUTPUT_SET(DSPORT, 0);     // 拉低总线
        os_delay_us(1);                 // 延时>1us
        GPIO_OUTPUT_SET(DSPORT, 1);     // 主机输出高电平
        os_delay_us(80);                // 60us < Tx “1”
    } else {
        GPIO_OUTPUT_SET(DSPORT, 0);     // 主机拉低总线
        os_delay_us(80);                // 60us < Tx “0” < 120us
        GPIO_OUTPUT_SET(DSPORT, 1);     // 主机释放总线,恢复高电平
        os_delay_us(1);					// TREC > 1us
	}
}

/* 写一字节数据 */
void ICACHE_FLASH_ATTR write_byte(uint8_t val) {
    uint8_t i, bit;
    for (i=0;i<8;i++) {     // 写入一个字节的数据,一个时序中写一次
     bit=val>>i;            // 右移i位
     bit&=0x01;             // 复制那位数据到temp
     write_bit(bit);        // 调用write_bit
    }
}

/* 读一位数据 */
uint8_t ICACHE_FLASH_ATTR read_bit(void) {
    uint8_t bit;
    GPIO_OUTPUT_SET(DSPORT, 0);     // 拉低总线,开始读时序
    os_delay_us(1);                 // 读数据之前先把总线拉低>1us
    GPIO_OUTPUT_SET(DSPORT, 1);     // 释放总线
    os_delay_us(11);                // 延时到采样位置
    bit = GPIO_INPUT_GET(DSPORT);   // 获取总线值
    os_delay_us(48);                // 延时以完成此次读时序60us
    return(bit);                    // 返回总线值
}

/* 读一字节数据 */
uint8_t ICACHE_FLASH_ATTR read_byte(void) {
    uint8_t i,value=0;
    for(i=0;i<8;i++) {
        if(read_bit())      // 读一字节数据,一个时序中读一次,并作移位处理
        value|=0x01<:%d\r\n", ack);
	// 18B20内部温度转换
    write_byte(0xcc);       // 仅一个DS18b20,跳过ROM
    write_byte(0x44);       // 温度转换
    delay_1ms(700);         // 延时>600ms
	ds18b20_reset();        // 复位,每一次读写之前都要对DS18B20进行复位操作
	write_byte(0xcc);       // 仅一个DS18b20,跳过ROM
	write_byte(0xbe);       // 读温度数据
    lsb = read_byte();      // 读LSB
    msb = read_byte();      // 读MSB
    temp = msb;
    temp <<= 8;
    temp |= lsb;

    return temp;
}

程序的用法请看《ESP8266_SDK发送温度数据到阿里云》一文。

3. 操作18B20的时序

3.1 逻辑分析仪设置

测试仪器是广州致远的LA1016逻辑分析仪。下面是触发和采样设置。

ESP8266接温度传感器18B20时序校准_第1张图片

ESP8266接温度传感器18B20时序校准_第2张图片

3.2 初始化时序

  • 复位即应答关系时序图

ESP8266接温度传感器18B20时序校准_第3张图片

  • 代码
    GPIO_OUTPUT_SET(DSPORT, 0);     // 将总线拉低480us-960us ,总线上所有器件都将被复位
    os_delay_us(495);               // 保持低电平,使得MASTER Tx > 480us
    GPIO_OUTPUT_SET(DSPORT, 1);     // 拉高电平,释放总线,如果DS18B20做出反应将在15us~60us后拉低总线
    os_delay_us(80);                // 等待DS18B20拉低总线
    uint8_t ack = GPIO_INPUT_GET(DSPORT);   // 获取总线状态
    os_delay_us(380);               // 调节MASTER TR > 480us
    return(ack);                    // 成功返回0,失败返回1
  • 波形

ESP8266接温度传感器18B20时序校准_第4张图片

T从第一个下降沿开始采样

M1-T是MASTER Tx,主机拉低总线时间496us > 480us

M1主机拉高,释放总线

M2-M1 DS18B20从总线释放后30.1us开始应答,即拉低总线

M3-M2 DS18B20应答持续时间100.5us,我们在从M1开始的80us处采样即可

M3 DS18B20拉高释放总线

M3-M4延时用来调节MASTER Rx

M4-M1是MASTER Rx=508.4us > 480us

3.3 写操作

3.3.1 写1位和读1位时序图

ESP8266接温度传感器18B20时序校准_第5张图片

3.3.2 写1位数据

  • 写“0”
        GPIO_OUTPUT_SET(DSPORT, 0);     // 主机拉低总线
        os_delay_us(80);                // 60us < Tx “0” < 120us
        GPIO_OUTPUT_SET(DSPORT, 1);     // 主机释放总线,恢复高电平
        os_delay_us(1);		  // TREC > 1us

ESP8266接温度传感器18B20时序校准_第6张图片

M1主机拉低总线

M2-M1 60us < Tx “0”=80.9us < 120us

M2主机释放总线

M3-M2 TREC > 1us

  • 写“1”
        GPIO_OUTPUT_SET(DSPORT, 0);     // 拉低总线
        os_delay_us(1);                 // 延时 > 1us
        GPIO_OUTPUT_SET(DSPORT, 1);     // 主机输出高电平
        os_delay_us(80);                // 60us < Tx “1”

ESP8266接温度传感器18B20时序校准_第7张图片

M1 拉低总线

M2-M1延时 > 1us

M2主机输出高电平

M3-M2 = 81.4us > 60us

3.3.3 写1字节数据0xcc(1100 1100)

注意小端先写,也就是从右向左一位一位写0011 0011。

void ICACHE_FLASH_ATTR write_byte(uint8_t val) {
    uint8_t i, bit;
    for (i=0;i<8;i++) {     // 写入一个字节的数据,一个时序中写一次
     bit=val>>i;            // 右移i位
     bit&=0x01;             // 复制那位数据到temp
     write_bit(bit);        // 调用write_bit
    }
}

3.3.4 发送温度转换命令

    write_byte(0xcc);       // 仅一个DS18b20 ,跳过ROM
    write_byte(0x44);       // 温度变换
    delay_1ms(700);         // 延时>600ms

3.4 读操作

3.4.1 发送读温度命令

    ds18b20_reset();        // 复位,每一次读写之前都要对DS18B20进行复位操作
    write_byte(0xcc);       // 仅一个DS18b20,跳过ROM
    write_byte(0xbe);       // 读温度数据

3.4.2 读1位数据

    uint8_t bit;
    GPIO_OUTPUT_SET(DSPORT, 0);     // 拉低总线,开始读时序
    os_delay_us(1);                 // 读数据之前先把总线拉低>1us
    GPIO_OUTPUT_SET(DSPORT, 1);     // 释放总线
    os_delay_us(11);                // 延时到采样位置
    bit = GPIO_INPUT_GET(DSPORT);   // 获取总线值
    os_delay_us(48);                // 延时以完成此次读时序60us
    return(bit);                    // 返回总线值
  • 读数据“0”

ESP8266接温度传感器18B20时序校准_第8张图片

M1主机拉低总线,持续1us后释放总线

M2-M1 DS18B20拉低总线,输出数据0,主机在M1之后12usc处采样

M2 DS18B20释放总线

M3-M2主机上拉,高电平

M3-M1读取周期为62.2us > 60us

  • 读“1”

ESP8266接温度传感器18B20时序校准_第9张图片

M1主机拉低总线

M2-M1持续1us后释放总线

M3-M2 DS18B20释放总线,主机上拉到高电平,主机在M1之后12usc处采样

M3-M1读取周期为63.2us > 60us

3.4.3 读1个字节数据

注意低位先读。

    uint8_t i,value=0;
    for(i=0;i<8;i++) {
        if(read_bit())      // 读一字节数据,一个时序中读一次,并作移位处理
        value|=0x01<
  • 读2个字节的温度数据
    lsb = read_byte();      // 读LSB
    msb = read_byte();      // 读MSB

      1     0      1      1      0      0     1      1      1     0      0      0      0     0     0      0     

大小端转换:

0000 0001 1100 1101

前5位是符号位,0表示正数。

001 1100 1101 = 461

转换成温度值:461/16 = 28.81℃

串口显示,请看前面概述中提到的《ESP8266_SDK发送温度数据到阿里云》一文。

 

你可能感兴趣的:(ESP8266,SDK,物联网,DS18B20)