0%

DS18B20外设驱动

应用最广泛的测温传感器

简介

DS18B20通过1-Wire总线进行通信,根据定义,该总线仅需要一条数据线(和地线)即可与中央微处理器进行通信。它的工作温度范围为 -55°C 至 +125°C,在–10°C 至 +85°C 的范围内精确至 0.5°C。 此外,DS18B20可以直接从数据线获取电源(“寄生电源”),而无需外部电源。

每个DS18B20都有一个唯一的64位串行代码,它允许多个DS18B20在同一条1线总线上工作。 因此,使用一个微处理器控制分布在大面积上的许多DS18B20就很简单,DS18B20也由此成为温控系统中最常用的传感器。


温度测量工作原理

  • 使用DS18B20时可以将温度传感器的分辨率配置为9、10、11或12位,分别对应于0.5C,0.25C,0.125C和0.0625C的增量;
  • 要启动温度测量和a-D转换,主机必须发出Convert T[44h]命令;
  • 转换后,产生的热数据存储在草稿行内存中的2字节温度寄存器中,DS18B20返回到空闲状态。

寄存器格式

  • DS18B20输出温度数据以摄氏度校准,温度数据以16位符号扩展2的补码形式存储在温度寄存器中;
  • 符号位表示温度是正还是负:正数S=0,负数S=1;
  • 如果DS18B20配置为12位分辨率,则温度寄存器中的所有位都将包含有效数据;
  • 分辨率位为1,代表加上该位的一个增量。

LS Byte:

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
2^3 2^2 2^1 2^0 2^-1 2^-2 2^-3 2^-4

MS Byte

bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
S S S S S 2^6 2^5 2^4

温度/DATA关系表(示例)

温度 数字信号输出(二进制) 数字信号输出(十六进制) 计算过程
+125°C 0000 0111 1101 0000 07D0h 2^0+2^2+2^3+2^4+2^5+2^6=125
+85°C 0000 0101 0101 0000 0550h 2^0+2^2+2^4+2^6=85
+25.0625°C 0000 0001 1001 0001 0192h 2^-4+2^0+2^3+2^4=25.0625
+10.125°C 0000 0000 1010 0010 00A2h 2^-3+2^1+2^3=10.125
+0.5°C 0000 0000 0000 1000 0008h 2^-1=0.5
0°C 0000 0000 0000 0000 0000h 0
-0.5°C 1111 1111 1111 1000 FFF8h 2^-1=0.5
-10.125°C 1111 1111 0101 1110 FF5Eh 2^-3+2^1+2^3=10.125
-25.0625°C 1111 1110 0110 1111 FE6Fh 2^-4+2^0+2^3+2^4=25.0625
-55°C 1111 1100 1001 0000 FC90h 2^0+2^2+2^3+2^4+2^5+2^6=125

寄存器指令

DS18B20的操作顺序为:

  1. 复位指令

  2. ROM指令

    image-20201224163342870
  3. DS18B20功能指令

    image-20201224163247580

常用ROM指令:

SKIP ROM [CCh]:主机可以使用该命令同时寻址总线上的所有设备,而无需发送任何ROM代码信息。

​ 用法1:通过允许主机从机读取而不发送设备的64位ROM代码来节省时间(只有在总线上只有一个从设备时可用)

1
2
3
4
5
ds_write_byte(bus,0xcc);
ds_write_byte(bus,0xbe);
//主机读取暂存器的信息,从字节0的最低有效位开始一直到暂存器直到读取第9个字节(8-0)
//只有在总线上只有DS18B20的时候,[BEh]指令才能跟随在[CCh]指令之后;否则冲突
//在这种情况下,可以允许主机从从机读取数据而不发送设备的64位ROM代码来节省时间

​ 用法2:主机可以通过发出Skip ROM命令和随后的Convert T [44h]命令,使总线上的所有DS18B20都同时执行温度转换

1
2
3
4
ds_write_byte(bus,0xcc);
//跳过ROM代码信息的发送
ds_write_byte(bus,0x44);
//使总线上所有DS18B20都同时执行温度转换

常用功能指令:

CONVERT T [44h]:该命令启动一次温度转换。 转换后,产生的热数据被存储在暂存器的2字节温度寄存器中,DS18B20返回其低功耗空闲状态。

**WRITE SCRATCHPAD [4Eh]: **该命令允许主机将3个字节的数据写入DS18B20的暂存器。 第一个数据字节写入TH寄存器(暂存器的字节2),第二个字节写入TL寄存器(字节3),第三个字节写入配置寄存器(字节4)。

READ SCRATCHPAD [BEh] :该命令允许主机读取暂存器的内容。 数据传输从字节0的最低有效位开始,一直到暂存器,直到读取第9个字节(字节8 – CRC)

image-20201224163128270

MSP430程序

<DS18B20.h>:

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef WL_DS18B20_H
#define WL_DS18B20_H

enum DS18B20_BUS_DEF //枚举
{
DS18B20_BUS_1, //枚举第一项默认为0
DS18B20_BUS_DEF_END //1
};

void tem_change(uint8 bus);
float get_temperature(uint8 bus);

#endif

<DS18B20.c>:

  1. 引脚操作函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void set_ds_output(uint8 bus)
    {
    switch(bus)
    {
    case DS18B20_BUS_1:
    P7DIR |= BIT2; //P7.3设置为输出
    break;
    default:
    break;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void set_ds_input(uint8 bus)
    {
    switch(bus)
    {
    case DS18B20_BUS_1:
    P7DIR &= ~BIT2; //P7.3设置为输入
    break;
    default:
    break;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void set_ds_high(uint8 bus)
    {
    switch(bus)
    {
    case DS18B20_BUS_1:
    P7OUT |= BIT2; //P7.2拉高
    break;
    default:
    break;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void set_ds_low(uint8 bus)
    {
    switch(bus)
    {
    case DS18B20_BUS_1:
    P7OUT &= ~BIT2; //P7.2拉低
    break;
    default:
    break;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    uint8 read_ds(uint8 bus)
    {
    uint8 data;
    switch(bus)
    {
    case DS18B20_BUS_1:
    data=(P7IN & BIT2)?1:0;
    break;
    default:
    break;
    }
    return data;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    void Reset_18b20(uint8 bus) 
    {
    set_ds_output(bus);
    set_ds_high(bus);
    delay_us(1); //1us
    set_ds_low(bus);
    delay_us(550); //当总线停留在低电平超过480us,总线上所有器件都将被复位,这里
    //延时约530us总线停留在低电平超过480μs,总线上的所有器件都将被复位。

    set_ds_high(bus); //产生复位脉冲后,微处理器释放总线,让总线处于空闲状态,原因查18b20中文资料

    delay_us(45);; //释放总线后,以便从机18b20通过拉低总线来指示其是否在线
    //存在检测高电平时间:15~60us,所以延时44us,进行1-wire presence //detect(单线存在检测)

    set_ds_input(bus);
    if(read_ds(bus)==0)
    ds18b20_flag=1; //detect 18b20 success
    else
    ds18b20_flag=0; //detect 18b20 fail
    delay_us(28); //存在检测低电平时间:60~240us,所以延时约140us
    set_ds_output(bus);

    set_ds_high(bus); //再次拉高总线,让总线处于空闲状态
    delay_us(50);
    }

  2. 读写操作函数

    读/写时间隙:DS1820 的数据读写是通过时间隙处理位和命令字来确认信息交换。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    uint8 ds_read_bit(uint8 bus)    //读一位
    {
    uint8 dat;
    set_ds_output(bus);
    set_ds_low(bus); //单片机(微处理器)将总线拉低
    delay_us(1); //读时隙起始于微处理器将总线拉低至少1us
    set_ds_high(bus); //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
    delay_us(1);
    //小延时一下,读取18b20上的数据 ,因为从ds18b20上输出的数据
    //在读"时间隙"下降沿出现15us内有效
    set_ds_input(bus);
    dat=read_ds(bus); //主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现15us内有效
    delay_us(77); //所有读"时间隙"必须60~120us,这里77us
    return(dat); //返回有效数据
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    uint8 ds_read_byte(uint8 bus ) 	 //读一字节
    {
    uint8 value,i,j;
    value=0; //给初值
    for(i=0;i<8;i++)
    {
    j=ds_read_bit(bus);
    value=(j<<7)|(value>>1); //这一步的说明在一个word文档里面
    }
    return(value); //返回一个字节的数据
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void ds_write_bit(uint8 bus,uint8 dat)
    {
    if(dat) //写 1
    {
    set_ds_low(bus);
    delay_us(2);
    //asm("NOP"); //看时序图,至少延时1us,才产生写"时间隙"
    set_ds_high(bus); //写时间隙开始后的15μs内允许数据线拉到高电平
    delay_us(70); //所有写时间隙必须最少持续60us
    }
    else //写 0
    {
    set_ds_low(bus);
    delay_us(64); //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,这里64us
    set_ds_high(bus);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    void ds_write_byte(uint8 bus,uint8 dat) //写一个字节
    {
    uint8 i;
    uint8 onebit; //一定不要忘了,onebit是一位
    for(i=1;i<=8;i++)
    {
    onebit=dat&0x01;
    dat=dat>>1;
    if(onebit) //写 1
    {
    set_ds_low(bus);
    delay_us(2);
    //asm("NOP"); //看时序图,至少延时1us,才产生写"时间隙"
    set_ds_high(bus); //写时间隙开始后的15μs内允许数据线拉到高电平
    delay_us(70); //所有写时间隙必须最少持续60us
    }
    else //写 0
    {
    set_ds_low(bus);
    delay_us(64); //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,这里64us
    set_ds_high(bus);
    }
    }
    }

  3. 温度功能函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void tem_change(uint8 bus)
    {
    Reset_18b20(bus);
    delay_us(100); //约2ms
    ds_write_byte(bus,0xcc);
    //跳过ROM代码信息的发送
    ds_write_byte(bus,0x44);
    //使总线上所有DS18B20都同时执行温度转换
    }

    获取温度函数,返回值为一个十进制的温度值,精度为0.0625

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    float get_temperature(uint8 bus)
    {
    uint8 a,b;
    Reset_18b20(bus);
    delay_us(150); //约2ms
    ds_write_byte(bus,0xcc);
    ds_write_byte(bus,0xbe);
    //主机读取暂存器的信息,从字节0的最低有效位开始一直到暂存器直到读取第9个字节(8-0)
    //只有在总线上只有DS18B20的时候,[BEh]指令才能跟随在[CCh]指令之后;否则冲突
    //在这种情况下,可以允许主机从从机读取数据而不发送设备的64位ROM代码来节省时间

    a=ds_read_byte(bus);
    b=ds_read_byte(bus);
    tempDS18B20=b;
    tempDS18B20<<=8;
    tempDS18B20=tempDS18B20|a;
    biaozhi=0;
    if((tempDS18B20&0x8000))
    {
    biaozhi=1;//设置温度正负的标志
    tempDS18B20=(~tempDS18B20+1);
    tempDS18B20&=0x07FF;
    }
    wendu=tempDS18B20*0.0625; //得到真实十进制温度值,因为DS18B20
    //可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
    // wendu=wendu*10.0+0.5; //放大十倍,这样做的目的将小数点后第一位
    //也转换为可显示数字,同时进行一个四舍五入操作。
    //tempDS18B20=(unsigned long int)(wendu*100+0.5);

    if(biaozhi)
    //tempDS18B20 |= 0x8000;
    wendu*=(-1);
    Reset_18b20(bus);
    return wendu;
    }
两种颜色的功德箱(逃