暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

DS18B20温度传感器时序图解析(STM32)

程序员小哈 2020-06-12
704

网上DS18B20的驱动实现代码一大堆,简简单单的就能够移植成功,获得温度值,但是为什么代码这么写?为什么要延时那么长的时间?不对照手册仔细分析时序图,还真是不明白为什么。

下面我们就来详细剖析一下DS18B20的驱动函数的实现。

DS18B20 简介

DS18B20数字温度传感器是美国DALLAS公司生产的单总线数字温度传感器。其测温范围为-55℃~+125℃(-67℉~+257℉),64位只读存储器的片序列号。从而允许多只DS18B20同时并联在一根单线总线上;

华氏度和摄氏度换算关系:

(华氏度-32)×5÷9=摄氏度

DS18B20可以用一个微控制器的GPIO引脚去控制。器件内部高速暂存器区含有两个字节的温度寄存器,用来存储温度传感器输出的数据。

此外,高速暂存器区还有上下温度报警寄存器(TH和TL),和一个字节的配置寄存器。

配置寄存器允许用户将温度的精度设置为9~12位对应的分辨率为0.5℃、0.25℃、0.125℃、0.0625℃。上电默认为12位转换精度。

  • DS18B20存储器图

实际使用中,当只是为了测温,只需用到字节1,字节2和字节5。应用环境中如果没有强干扰,不是十分严格的话,不做校验也可以。

其中,暂存寄存器中的字节5包含着配置寄存器,配置寄存器内容如下图所示:

用户通过改变上表中R0和R1的值来配置DS18B20的分辨率。上电默认为R0=1及R1=1(12位分辨率)。

  • 温度/数据对应表:

温度转换后,温度转换的值将会保存在暂存存储器的温度寄存器中,并且DS18B20将会恢复到闲置状态。

TH,TL和配置寄存器是EEPROM,存储的数据在器件掉电时不会消失。

DS18B20的另一个功能是可以在没有外部电源供电的情况下工作。当总线处于高电平状态,DQ与上拉电阻连接通过单总线对器件供电。

同时处于高电平状态的总线信号对内部电容(Cpp)充电,在总线处于低电平状态时,该电容提供能量给器件。

这种提供能量的形式被称为“寄生电源”;

寄生电源模式时,VDD引脚必须接地。

  • “寄生电源”供电方式
  • 外部电源供电方式

原理图

外观及封装

  • TO-92封装
  • 防水型不锈钢封装

采用导热性高的密封胶灌封,保证了温度传感器的高灵敏性,极小的温度延迟。

芯片每个引脚均用热缩管隔开,防止短路,内部封胶,防水防潮。

引脚说明
红线:VCC
绿线:GND
黄线:DQ,传感器数据总线

驱动实现

INITIALIZATION TIMING

在初始化序列期间,总线控制器拉低总线并保持至少480us以发送一个复位脉冲,返回释放总线,进入接收状态(等待DS18B20应答)。

总线释放后,单总线由上拉电阻拉到高电平。

当DS18B20探测到I/O引脚上的上升沿后,等待15-60us,然后其以拉低总线60-240us的方式发出存在脉冲。至此,初始化时序完毕。

所以,初始化成功的标志就是能否读到DS18B20这个先低后高的脉冲时序,并且拉低的时间要满足60-240us。

复位DS18B20的代码如下:

    //复位DS18B20
    void DS18B20_Rst(void)
    {
    DS18B20_IO_OUT(); //总线设置为输出模式
    DS18B20_DQ_OUT=0; //主机拉低总线
    delay_us(750);
    DS18B20_DQ_OUT=1; //释放总线,产生的上升沿能被DS18B20检测到
    delay_us(15); //延时15us之后,等待DS18B20发送的低电平信号到达。
    }


    //等待DS18B20的回应
    //返回1:未检测到DS18B20的存在
    //返回0:存在
    u8 DS18B20_Check(void)
    {
    u8 retry=0;
    DS18B20_IO_IN(); //总线设置为输入模式

    while (DS18B20_DQ_IN&&retry<200) //等待拉低总线60-240us的低电平
    {
    retry++;
    delay_us(1);
    };


    if(retry>=200)return 1;
    else retry=0;
    while (!DS18B20_DQ_IN&&retry<240)
    {
    retry++;
    delay_us(1);
    };
    if(retry>=240)
    return 1;


    return 0;
    }

    READ/WRITE TIME SLOT TIMING DIAGRAM

    DS18B20的写时序(见下图):

    主机在写时隙向DS18B20写入数据,其中分为写”0”时隙,和写”1”时隙。总线主机使用写“1”时间隙向DS18B20写入逻辑1,使用写“0”时间隙向DS18B20写入逻辑0。

    所有的写时隙必须有最少60us的持续时间,相邻两个写时隙必须要有最少1us的恢复时间。两种写时隙都通过主机拉低总线产生(见下图)。

    为了产生写1时隙,在拉低总线后主机必须在15μs内释放总线。在总线被释放后,由于上拉电阻将总线恢复为高电平。

    为了产生写”0”时隙,在拉低总线后主机必须继续拉低总线以满足时隙持续时间的要求(至少60μs)。

    在主机产生写时隙后,DS18B20会在其后的15~60us的一个时间段内采样单总线(DQ)。在采样的时间窗口内,如果总线为高电平,主机会向DS18B20写入1;如果总线为低电平,主机会向DS18B20写入0。

    综上所述,所有的写时隙必须至少有60us的持续时间。相邻两个写时隙必须要有最少1us的恢复时间。所有的写时隙(写0和写1)都由拉低总线产生。

      //写一个字节到DS18B20
      //dat:要写入的字节
      void DS18B20_Write_Byte(u8 dat)
      {
      u8 j;
      u8 testb;
      DS18B20_IO_OUT(); //设置DQ为输出模式
      for (j=1;j<=8;j++)
      {
      testb=dat&0x01;
      dat=dat>>1;
      if (testb)
      {
      DS18B20_DQ_OUT=0;// Write 1
      delay_us(2);
      DS18B20_DQ_OUT=1;
      delay_us(60);
      }
      else
      {
      DS18B20_DQ_OUT=0;// Write 0
      delay_us(60); // 等待DS18B20来采集信号
      DS18B20_DQ_OUT=1;
      delay_us(2);
      }
      }
      }

      DS18B20的读时序(见下图):

      主机发起读时序时,DS18B20仅被用来传输数据给控制器。因此,总线控制器在发出读指令后必须立刻开始读时序。

      所有读时序必须最少60us,包括两个读周期间至少1us的恢复时间。

      当总线控制器把数据线从高电平拉到低电平时,读时序开始,数据线必须至少保持1us,然后总线被释放。

      DS18B20 通过拉高或拉低总线来传输”1”或”0”。

      当传输逻辑”0”结束后,总线将被释放,通过上拉电阻回到上升沿状态。

      从DS18B20输出的数据在读时序的下降沿出现后15us 内有效。因此,总线控制器在读时序开始后必须把I/O口设置为输入模式,以读取I/O口状态。

      阴影部分为DS18B20释放总线的时刻,总线为空闲状态。

        //从DS18B20读取一个位
        //返回值:1/0
        u8 DS18B20_Read_Bit(void) // read one bit
        {
        u8 data;
        DS18B20_IO_OUT(); //设置总线为输出模式
        DS18B20_DQ_OUT=0;
        delay_us(2); //拉低最少1us
        DS18B20_DQ_OUT=1; //拉低再升高,产生读时序
        DS18B20_IO_IN(); //设置总线为输入模式
        delay_us(12);
        if(DS18B20_DQ_IN)data=1;
        else data=0;
        delay_us(50);
        return data;
        }


        //从DS18B20读取一个字节
        //返回值:读到的数据
        u8 DS18B20_Read_Byte(void) // read one byte
        {
        u8 i,j,dat;
        dat=0;
        for (i=1;i<=8;i++)
        {
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
        }
        return dat;
        }
        • DS18B20的功能命令
        • 获取温度值

        要获取温度值,我们需要发送上面功能命令0x44,然后发送读取暂存寄存器命令0xBE,然后我们只需要获得暂存器中的9个字节的前两个字节即可。

        要获得DS18B20的温度值,需要按照下表中的顺序依次发送功能命令。

        获取温度的具体代码实现如下:

          //开始温度转换
          void DS18B20_Start(void)// ds18b20 start convert
          {
          DS18B20_Rst();
          DS18B20_Check();
          DS18B20_Write_Byte(0xcc);// skip rom
          DS18B20_Write_Byte(0x44);// convert
          }


          //从ds18b20得到温度值
          //精度:0.1C
          //返回值:温度值 (-550~1250)
          short DS18B20_Get_Temp(void)
          {
          u8 temp;
          u8 TL,TH;
          short tem;
          DS18B20_Start (); // ds18b20 start convert
          DS18B20_Rst();
          DS18B20_Check();
          DS18B20_Write_Byte(0xcc);// skip rom
          DS18B20_Write_Byte(0xbe);// convert
          TL=DS18B20_Read_Byte(); // LSB
          TH=DS18B20_Read_Byte(); // MSB

          if(TH>7)
          {
          TH=~TH;
          TL=~TL;
          temp=0;//温度为负
          }else temp=1;//温度为正
          tem=TH; //获得高八位
          tem<<=8;
          tem+=TL;//获得底八位
          tem=(float)tem*0.625;//转换
          if(temp)return tem; //返回温度值
          else return -tem;
          }

          跳过ROM序列号检测命令(0xCCH),对于单片DS18B20在线的系统,该命令允许主机跳过ROM序列号检测而直接对寄存器操作,从而节省时间,对于多片DS18B20在线系统,该命令将引起数据冲突。

          如果主机只是对一个DS18B20进行操作,进而不需要读取ROM编码了,只要发送跳过ROM(0xCCH)命令,就可以进行温度转换和读取操作了。

          • 获取DS18B20内部ID序列号

          因为咱们总线上只有一个DS18B20设备,所以直接发送0x33指令即可READ ROM。

          DS18B20中有一个64位光刻ROM,按说明书说法,开始(最低)8位是产品类型标号,对于DS18B20来说都是(28H),接着的48位是该DS18B20自身的序列号,最后8位是前面56位的循环冗余校验码(CRC=X8+X5+X4+1)。

          光刻ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。

          读取ROM方法:先复位DS18B20,成功后执行读取ROM命令(33H),然后将这64位以8个字节的方式存入数组。

          获取DS18B20内部ID序列号的具体代码实现如下:

            DS18B20_Rst();
            DS18B20_Check();
            DS18B20_Write_Byte(0x33);

            for(i = 0; i < 8;i++)
            {
            arrDS18B20ID[i] = DS18B20_Read_Byte();
            }

            sprintf((char *)dtbuf,"DS18B20 ID is %02X %02X %02X %02X %02X %02X %02X %02X\r\n", arrDS18B20ID[0], arrDS18B20ID[1], arrDS18B20ID[2], arrDS18B20ID[3], arrDS18B20ID[4], arrDS18B20ID[5], arrDS18B20ID[6], arrDS18B20ID[7]);


            printf((u8 *)dtbuf,strlen((char *)dtbuf));

            我手里的两个DS18B20得到的结果如下所示:

            由上可以看出,首字节都是0x28,即产品类型都是一样的。


            至此,六月份的智能风扇中的温度传感器模块的已经实现了哈。


            推荐阅读:
            STM32单片机最小系统详解
            STM32F103 串口的使用方法
            STM32中精确延时函数的实现
            DHT11及DHT21温湿度传感器时序图解析(STM32)
            基于STM32固件库的MDK5工程建立
            修改Keil工程名称并添加其他模块文件
            基于单片机的智能风扇的功能点及所需要的功能模块【2020.06每月活动】

            资料下载

            微信公众号后台回复“温度传感器”,可以下载工程源码及DS18B20的手册。



            文章转载自程序员小哈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论