• MCU 51-9 DS18B20 Temperature Sensor


    DS18B20特点

    通信采用1-Wire接口

    每个DS18B20都有唯一的64位序列码储存在板载ROM中

    无需外部元件

    可从数据线供电,电源范围为3.0V ~ 5.5V。

    可测量的温度范围在-55℃ ~ +125℃

    在-10~+85℃范围内精确度为±0.5℃

    温度计分辨率可设置为9~12位,12位时分辨率对应为0.0625℃

     

    单总线时序

    DS18B20采用1-wire Bus所有数据都在一条线上传输,因此单总线协议对时序要求非常严格以确保数据的完整性。

    单总线信号类型:复位脉冲、存在脉冲、写0、写1、读0、读1。所有这些信号除存在脉冲由DS18B20发出的以外其他信号都由总线控制器发出。

    数据传输总是从最低有效位开始。

    初始化时序

    初始化时序里面包含了复位DS18B20和接收DS18B20返回的存在信号。

    主机和DS18B20做任何通讯前都需要对其初始化。初始化期间,总线控制器拉低总线并保持480us以上挂在总线上的器件将被复位,然后释放总线,等到15-60us,此时18B20将返回一个60-240us之间的低电平存在信号。

    写时序

    写时序分为写0时序和写1时序。

    总线控制器通过控制单总线高低电平持续时间从而把逻辑1或0写DS18B20中。

    总线控制器要产生一个写时序,必须将总线拉低最少1us,产生写0时序时总线必须保持低电平60~120us之间,然后释放总线,产生写1时序时在总线产生写时序后的15us内允许把总线拉高。注意:2次写周期之间至少间隔1us

     

    读时序

    读时序分为读0时序和读1时序。

    总线控制器通过读取由DS18B20控制的总线高低电平接收DS18B20数据。

    总线控制器要产生一个读时序,必须将总线拉低至少1us,然后释放总线,在读信号开始后15us内总线控制器采样总线数据,读一位数据至少保持在60us以上。注意:2次读周期之间至少间隔1us

    读1详细时序图

    DS18B20暂存器

    温度寄存器图表

     

    配置寄存器图表

     

    部分ROM指令及功能指令

    忽略ROM指令(CCh)

    这条指令允许总线控制器不用提供64 位ROM 编码就使用功能指令。例如,总线控制器可以先发出一条忽略ROM 指令,然后发出温度转换指令[44h],从而完成温度转换操作。在单点总线(总线上只有一个DS18B20)情况下使用该命令,器件无需发回64 位ROM 编码,从而节省了时间。如果总线上有不止一只从机,若发出忽略ROM指令,由于多只从机同时传送信号,总线上就会发生数据冲突。

    温度转换指令(44h)

    这条命令用以启动一次温度转换。温度转换指令被执行,产生的温度转换结果数 据以2个字节的形式被存储在高速暂存器中,而后DS18B20保持等待状态。

    读暂存器指令(BEh)

    这条命令读取暂存器的内容。读取将从字节0 开始,一直进行下去,直到读完暂存器所有字节,如果不想读完所有字节,控制器可以在任何时间发出复位命令来中止 读取。

    写暂存器指令(4Eh)

    这条命令向DS18B20 的暂存器写入数据,开始位置在TH 寄存器(暂存器的第2 个字节),接下来写入TL 寄存器(暂存器的第3 个字节),最后写入配置寄存器 (暂存器的第4 个字节)

    拷贝暂存器指令(48h)

    这条命令把TH,TL 和配置寄存器(第2、3、4 字节)的内容拷贝到EEPROM 中。

    执行顺序:

    (1)初始化

    (2)ROM操作指令

    (3)DS18B20功能指令温度转换命令、 读取暂存器命令

    #include <reg52.h>
    #include <intrins.h>
    #define MAIN_Fosc        11059200UL    //宏定义主时钟HZ
    /*====================================
     自定义类型名
    ====================================*/
    typedef unsigned char INT8U;
    typedef unsigned char uchar;
    
    typedef unsigned int INT16U;
    typedef unsigned int uint;
    
    /*====================================
     硬件接口位声明
    ====================================*/
    sbit DS  = P2^2;   //DS18B20单总线
    sbit DU  = P2^6;   //数码管段选
    sbit WE  = P2^7;   //数码管位选
    /*====================================
    共阴极数码管段选码
    ====================================*/
    uchar code table[]={ 
    //0        1     2     3     4     5     6     7     8
    0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,
    //9     A     B       C     D       E     F        -     .      关显示
    0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x40, 0x80, 0x00
                       };
    
    /*====================================
    数码管位选码
    ====================================*/
                      //第1位    2位      3位     4位   5位    6位      7位    8位
    uchar code T_COM[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};//数码管位码
    
    /*====================================
    函数:void Delay_Ms(INT16U ms)
    参数:ms,毫秒延时形参
    描述:12T 51单片机自适应主时钟毫秒级延时函数
    ====================================*/
    void Delay_Ms(INT16U ms)
    {
         INT16U i;
         do{
              i = MAIN_Fosc / 96000; 
              while(--i);   //96T per loop
         }while(--ms);
    }
    /*us延时函数,执行一次US--所需6.5us进入一次函数需要11.95us*/
    void Delay_us(uchar us)
    {
        while(us--);    
    }
    /*====================================
    函数:void Display(INT16U Value)
    参数:Value,显示值 取值0-65535
    描述:共阴极数码管显示函数可显示一个字节的数
    ====================================*/
    void Display(INT16U Value)            //注意由于需要显示的数大于一个字节所有形参需为int型
    {    
    //------------------------------
        DU = 0;                            //关闭段选
        P0 = table[Value/100];        //数码管显示百位
        DU = 1;                            //打开段选
        DU = 0;                            //关闭段选
    
        WE = 0;                        //关闭位选
        P0 = T_COM[0];                   //第一位数码管
        WE = 1;                        //打开位选
        WE = 0;                        //关闭位选
        Delay_Ms(3);
    //-------------------------------
        DU = 0;
        P0 = table[Value%100/10]|0x80; //显示十位
        DU = 1;
        DU = 0;
    
        WE = 0;
        P0 = T_COM[1];              //第二位数码管
        WE = 1;
        WE = 0;
        Delay_Ms(3);
    //-------------------------------
        DU = 0;
        P0 = table[Value%10];        //显示个位
        DU = 1;
        DU = 0;
    
        WE = 0;
        P0 = T_COM[2];                //第三位数码管
        WE = 1;
        WE = 0;
        Delay_Ms(3);
    }
    /*单总线初始化时序*/
    bit ds_init()
    {
        bit i;
        DS = 1;
        _nop_();
        DS = 0;
        Delay_us(75); //拉低总线499.45us 挂接在总线上的18B20将会全部被复位
        DS = 1; //释放总线
        Delay_us(4); //延时37.95us 等待18B20发回存在信号
        i = DS;
        Delay_us(20); //141.95us
        DS = 1;
        _nop_();
        return (i);
    }
    /*写一个字节*/
    void write_byte(uchar dat)
    {
        uchar i;
        for(i=0;i<8;i++)
        {
            DS = 0;
            _nop_();//产生些时序
            DS = dat & 0x01;
            Delay_us(10);//76.95us
            DS = 1; //释放总线准备下一次数据写入
            _nop_();
            dat >>= 1;
        }
    }
    
    uchar read_byte()
    {
        uchar i, j, dat;
        for(i=0;i<8;i++)
        {
            DS = 0;
            _nop_();//产生读时序
            DS = 1;
            _nop_();//释放总线
            j = DS;
            Delay_us(10);//76.95us
            DS = 1;
            _nop_();
            dat = (j<<7)|(dat>>1);    
        }
        return (dat);
    }
    void main()
    {
        uint i;
        uchar L, M;
    /*    ds_init();//初始化DS18B20
        write_byte(0xcc);//发送跳跃ROM指令
        write_byte(0x4e);//写暂存器指令
        write_byte(0x7f);
        write_byte(0xf7);
        write_byte(0x1f);//配置工作在9位模式下
        ds_init();//初始化DS18B20
        write_byte(0xcc);//发送跳跃ROM指令 
        write_byte(0x48);*/
        while(1)
        {
            ds_init();//初始化DS18B20
            write_byte(0xcc);//发送跳跃ROM指令
            write_byte(0x44);//发送温度转换指令
            ds_init();//初始化DS18B20
            write_byte(0xcc);//发送跳跃ROM指令
            write_byte(0xbe);//读取DS18B20暂存器值
            L = read_byte();
            M = read_byte();
            i = M;
            i <<= 8;
            i |= L;                        
            i = i * 0.0625 * 10 + 0.5;
            Display(i);
        }
    }
    /*
    DS18B20测温程序数码管显示
    可测温显示范围为-55℃ 至 +125℃
    
    */
    #include <reg52.h>
    #include <intrins.h>
    #define MAIN_Fosc        11059200UL    //宏定义主时钟HZ
    /*====================================
     自定义类型名
    ====================================*/
    typedef unsigned char INT8U;
    typedef unsigned char uchar;
    
    typedef unsigned int INT16U;
    typedef unsigned int uint;
    
    /*====================================
     硬件接口位声明
    ====================================*/
    sbit DS  = P2^2;   //DS18B20单总线
    sbit DU  = P2^6;   //数码管段选
    sbit WE  = P2^7;   //数码管位选
    /*显示负号*/
    uchar s=0;
    /*====================================
    共阴极数码管段选码
    ====================================*/
    uchar code table[]={ 
    //0        1     2     3     4     5     6     7     8
    0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,
    //9     A     B       C     D       E     F        -     .      关显示
    0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x40, 0x80, 0x00
                       };
    
    /*====================================
    数码管位选码
    ====================================*/
                      //第1位    2位      3位     4位   5位    6位      7位    8位
    uchar code T_COM[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};//数码管位码
    
    /*====================================
    函数:void Delay_Ms(INT16U ms)
    参数:ms,毫秒延时形参
    描述:12T 51单片机自适应主时钟毫秒级延时函数
    ====================================*/
    void Delay_Ms(INT16U ms)
    {
         INT16U i;
         do{
              i = MAIN_Fosc / 96000; 
              while(--i);   //96T per loop
         }while(--ms);
    }
    /*us延时函数,执行一次US--所需6.5us进入一次函数需要11.95us*/
    void Delay_us(uchar us)
    {
        while(us--);    
    }
    /*====================================
    函数:void Display(unsigned long Value)
    参数:Value,显示值 32位
    描述:
    ====================================*/
    void Display(unsigned long Value)        
    {
        uchar i=0;
    //第一位数码管
    //------------------------------
        if(s == 0);                               //如果为负数则不显示
        else
        {        
            DU = 0;                            //关闭段选
            P0 = s;        
            DU = 1;                            //打开段选
            DU = 0;                            //关闭段选
        
            WE = 0;                        //关闭位选
            P0 = T_COM[i++];            
            WE = 1;                        //打开位选
            WE = 0;                        //关闭位选
            Delay_Ms(1);
        }
    //第二位数码管
    //------------------------------
        if(Value < 1000000);               //如果温度值百位为0则不显示
        else
        {
            DU = 0;                            //关闭段选
            P0 = table[Value/1000000];    
            DU = 1;                            //打开段选
            DU = 0;                            //关闭段选
        
            WE = 0;                        //关闭位选
            P0 = T_COM[i++];                
            WE = 1;                        //打开位选
            WE = 0;                        //关闭位选
            Delay_Ms(1);
        }
    //第三位数码管
    //------------------------------
        if(Value < 100000);                    
        else
        {
            DU = 0;                            //关闭段选
            P0 = table[Value%1000000/100000];        //数码管显示百位
            DU = 1;                            //打开段选
            DU = 0;                            //关闭段选
        
            WE = 0;                        //关闭位选
            P0 = T_COM[i++];                
            WE = 1;                        //打开位选
            WE = 0;                        //关闭位选
            Delay_Ms(1);
        }
    //第四位数码管
    //-------------------------------
        DU = 0;
    
        P0 = table[Value%100000/10000]|0x80;//显示温度小数点,温度值个位显示
    
        DU = 1;
        DU = 0;
    
        WE = 0;
        P0 = T_COM[i++];        
        WE = 1;
        WE = 0;
        Delay_Ms(1);
    //第五位数码管
    //-------------------------------
        DU = 0;                            //关闭段选
        P0 = table[Value%10000/1000];    
        DU = 1;                            //打开段选
        DU = 0;                            //关闭段选
    
        WE = 0;                        //关闭位选
        P0 = T_COM[i++];                
        WE = 1;                        //打开位选
        WE = 0;                        //关闭位选
        Delay_Ms(1);
    //第六位数码管
    //-------------------------------
        if((Value%100/10) == 0 && (Value%1000/100) == 0 ); 
        else
        {
            DU = 0;                            //关闭段选
            P0 = table[Value%1000/100];    
            DU = 1;                            //打开段选
            DU = 0;                            //关闭段选
        
            WE = 0;                        //关闭位选
            P0 = T_COM[i++];                
            WE = 1;                        //打开位选
            WE = 0;                        //关闭位选
            Delay_Ms(1);
        }
    //第七位数码管
    //-------------------------------
        if((Value%10) == 0 && (Value%100/10) == 0);
        else
        {
            DU = 0;                            //关闭段选
            P0 = table[Value%100/10];    
            DU = 1;                            //打开段选
            DU = 0;                            //关闭段选
        
            WE = 0;                        //关闭位选
            P0 = T_COM[i++];                
            WE = 1;                        //打开位选
            WE = 0;                        //关闭位选
            Delay_Ms(1);
        }
    //第八位数码管
    //-------------------------------
        if((Value%10) == 0 );
        else
        {
            DU = 0;                            //关闭段选
            P0 = table[Value%10];    
            DU = 1;                            //打开段选
            DU = 0;                            //关闭段选
        
            WE = 0;                        //关闭位选
            P0 = T_COM[i++];                
            WE = 1;                        //打开位选
            WE = 0;                        //关闭位选
            Delay_Ms(1);
        }
    }
    
    /*单总线初始化时序*/
    bit ds_init()
    {
        bit i;
        DS = 1;
        _nop_();
        DS = 0;
        Delay_us(75); //拉低总线499.45us 挂接在总线上的18B20将会全部被复位
        DS = 1; //释放总线
        Delay_us(4); //延时37.95us 等待18B20发回存在信号
        i = DS;
        Delay_us(20); //141.95us
        DS = 1;
        _nop_();
        return (i);
    }
    /*写一个字节*/
    void write_byte(uchar dat)
    {
        uchar i;
        for(i=0;i<8;i++)
        {
            DS = 0;
            _nop_();//产生些时序
            DS = dat & 0x01;
            Delay_us(10);//76.95us
            DS = 1; //释放总线准备下一次数据写入
            _nop_();
            dat >>= 1;
        }
    }
    
    uchar read_byte()
    {
        uchar i, j, dat;
        for(i=0;i<8;i++)
        {
            DS = 0;
            _nop_();//产生读时序
            DS = 1;
            _nop_();//释放总线
            j = DS;
            Delay_us(10);//76.95us
            DS = 1;
            _nop_();
            dat = (j<<7)|(dat>>1);    
        }
        return (dat);
    }
    void main()
    {
        unsigned long temp;
        uint i;
        uchar L, M;
        ds_init();//初始化DS18B20
        write_byte(0xcc);//发送跳跃ROM指令
        write_byte(0x4e);//写暂存器指令
        write_byte(0x7f);//TH用户字节
        write_byte(0xf7);//TL用户字节
        write_byte(0x7f);//配置工作在12位模式下
        ds_init();//初始化DS18B20
        write_byte(0xcc);//发送跳跃ROM指令 
        write_byte(0x48);//拷贝暂存器到温度传感器的EEPROM中
        while(1)
        {
            ds_init();//初始化DS18B20
            write_byte(0xcc);//发送跳跃ROM指令
            write_byte(0x44);//发送温度转换指令
            ds_init();//初始化DS18B20
            write_byte(0xcc);//发送跳跃ROM指令
            write_byte(0xbe);//读取DS18B20暂存器值
            L = read_byte();
            M = read_byte();
            //模拟显示-55度,实际测温需注解掉下面这两句
            //M = 0xfe;
            //L = 0x6f;
    
            i = M;
            i <<= 8;
            i |= L;        
            if(M >= 0x08)    //判断是否为负数
            { 
                i = ~i + 1;//负数是以补码的形式存放的需要我们需要取反加1
                s = 0x40;  //显示负数符号
            }
            else s = 0;       //为正数则不显示                
            temp = i * 0.0625 * 10000; //浮点型数据转换
            Display(temp);
        }
    }
  • 相关阅读:
    完整的网站开发技术学习建议
    在微信小程序中绘制图表(part2)
    原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
    第八届蓝桥杯第二题:等差素数列
    第七届蓝桥杯第四题:快速排序
    51Nod:1086背包问题 V2
    POJ:2386 Lake Counting(dfs)
    51Nod:1268 和为K的组合
    迭代器
    51Nod:1134 最长递增子序列
  • 原文地址:https://www.cnblogs.com/darren-pty/p/13299434.html
Copyright © 2020-2023  润新知