目录

1 温度传感器DS18B20的工作原理

2 一线通信接口的使用(单总线)

2.1 单总线系统

2.2 执行序列

2.3 单总线信号

3 DS18B20寄存器的配置

4 根据传感器使用说明书时序图编写驱动程序

4.1   根据时序图写代码

4.1.1 初始化

4.1.2 读写时序

4.1.3 单总线时序代码封装

4.2   15单片机DS18B20代码

4.3   51单片机DS18B20代码



1 温度传感器DS18B20的工作原理

DS18B20   可编程分辨率的单总线数字温度计

特征:

  • 独特的单线接口仅需一个端口引脚进行通讯
  • 每个器件有唯一的 64 位的序列号存储在内部存储器中
  • 简单的多点分布式测温应用
  • 无需外部器件
  • 可通过数据线供电。供电范围为 3.0V到 5.5V。
  • 测温范围为-55~+125℃(-67~+257℉)
  • 在-10~+85℃范围内精确度为±5℃
  • 温度计分辨率可以被使用者选择为9~12 位
  • 最多在 750ms 内将温度转换为 12 位数字
  • 用户可定义的非易失性温度报警设置
  • 报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件
  • 与 DS1822 兼容的软件
  • 应用包括温度控制、工业系统、消费品、温度计或任何热感测系统

说明:

DS18B20 数字温度计提供 9-12 位摄氏温度测量而且有一个由高低电平触发的可编程的不因电源消失而改变的报警功能。DS18B20 通过一个单线接口发送或接受信息,因此在中央处理器和 DS18B20 之间仅需一条连接线(加上地线)。它的测温范围为-55~+125℃,并且在-10~+85℃精度为±5℃。除此之外,DS18B20能直接从单线通讯线上汲取能量,除去了对外部电源的需求。
        每个 DS18B20 都有一个独特的 64 位序列号,从而允许多只 DS18B20 同时连在一根单线总线上;因此,很简单就可以用一个微控制器去控制很多覆盖在一大片区域的 DS18B20。这一特性在 HVAC 环境控制、探测建筑物、仪器或机器的温度以及过程监测和控制等方面非常有用。

 引脚说明:

  • GND   -地
  • DQ      -数据I/O
  • VDD    -可选电源电压
  • NC      -无连接

板载DS18B20位置 位号U5


2 一线通信接口的使用(单总线)

通信线只有一根,且可以挂载多个DS18B20

2.1 单总线系统

单总线系统包括一个总线控制器一个或多个从机。DS18B20 总是充当从机。当只有一只从机挂在总线上时,系统被称为“单点”系统;如果由多只从机挂在总线上,系统被称为“多点”。
        所有的数据和指令的传递都是从最低有效位开始通过单总线。

2.2 执行序列

通过单线总线端口访问 DS18B20 的协议如下:

  • 步骤1. 初始化
  • 步骤2. ROM 操作指令
  • 步骤3. DS18B20 功能指令

具体操作下面见代码

每一次 DS18B20 的操作都必须满足以上步骤,若是缺少步骤或是顺序混乱,器件将不会返回值。

例如这样的顺序:发起 ROM 搜索指令[F0h]和报警搜索指令[ECh]之后,总线控制器必须返回步骤 1。

2.3 单总线信号

DS18B20 需要严格的单总线协议以确保数据的完整性。协议包括集中单总线信号类型:复位脉冲、存在脉冲、写 0、写 1、读 0 和读 1。所有这些信号,除存在脉冲外,都是由总线控制器发出的。


3 DS18B20寄存器的配置

配置寄存器:

存储器的第 4 位为配置寄存器,其组织见图 8。用户可以通过按表 3 所示设置 R0和 R1 位来设定 DS18B20 的精度。上电默认设置:R0=1,R1=1(12 位精度)。注意:精度和转换时间之间有直接的关系。暂存器的位 7 和位 0-4 被器件保留,禁止写入;在读回数据时,它们全部表现为逻辑 1。

温度寄存器格式


4 根据传感器使用说明书时序图编写驱动程序

给DS18B20新建.c.h文件

本开发板DS18B20的数据引脚接到了P14

sbit OneWire_DQ = P1^4;

DS18B20 需要严格的单总线协议以确保数据的完整性

必要时可以在操作前关闭中断,操作结束后再开启中断!!!

4.1   根据时序图写代码

4.1.1 初始化

复位序列:复位和存在脉冲
和 DS18B20 间的任何通讯都需要以初始化序列开始,初始化序列见下图13。

一个复位脉冲跟着一个存在脉冲表明 DS18B20 已经准备好发送和接收数据。

在初始化序列期间,总线控制器拉低总线并保持 480us 以发出(TX)一个复位脉冲,然后释放总线,进入接收状态(RX)。单总线由 5K 上拉电阻拉到高电平。当DS18B20 探测到 I/O 引脚上的上升沿后,等待 15-60us,然后发出一个由 60-240us低电平信号构成的存在脉冲。

单总线初始化程序

void Delay480us()        //@11.0592MHz
{unsigned char i, j;i = 6; j = 38;do{while (--j);} while (--i);
}/*初始化主机 将总线拉低至少480us,然后释放总线,等待15~60us后,存在的 从机 会拉低总线60~240us以响应 主机之后 从机 将释放总线
*/
//单总线初始化时序
void OneWire_Init(void)
{unsigned char ackbit;unsigned char i;OneWire_DQ = 1;OneWire_DQ = 0; Delay480us();    //总线拉低480usOneWire_DQ = 1;                 //释放总线i = 138; while (--i);            //延时等待50usackbit = OneWire_DQ; Delay480us();   //应答位:读取一下是否为0,并且延时等待480us
}

最后的ackbit可以返回出去,验证初始化是否成功,这里我验证的没有成功,但是不影响后续程序

延时50us的程序

只需要赋值程序主题部分即可,上面用到的是这样的,差不多是50us

i = 135;    while (--i);

4.1.2 读写时序

读/写时序

DS18B20 的数据读写是通过时序处理位来确认信息交换的

写时序
由两种写时序:写 1 时序和写 0 时序。总线控制器通过写 1 时序写逻辑 1 到DS18B20,写 0 时序写逻辑 0 到 DS18B20。所有写时序必须最少持续 60us,包括两个写周期之间至少 1us 的恢复时间。当总线控制器把数据线从逻辑高电平拉到低电平的时候,写时序开始(下图)
总线控制器要生产一个写时序,必须把数据线拉到低电平然后释放,在写时序开始后的 15us 释放总线。当总线被释放的时候,5K 的上拉电阻将拉高总线。总控制器要生成一个写 0 时序,必须把数据线拉到低电平并持续保持(至少 60us)
总线控制器初始化写时序后,DS18B20 在一个 15us 到 60us 的窗口内对 I/O 线采样。如果线上是高电平,就是写 1。如果线上是低电平,就是写 0。

发送(写)一位

发送一位,即发送0或1,非0即1,下面有用到!

发送0和1时序的区别是在15us之后电平不同,我们可以根据这个不同点写这一段程序
先把总线拉低10us,然后把要发送的数据放在总线上,发0即保持低电平,发1即变成高电平,然后再延时50us满足时序长度,最终释放总线

/*发送一位主机将总线拉低60~120us,然后释放总线,表示发送0;主机将总线拉低1~15us,然后释放总线,表示发送1。从机 将在总线拉低30us后读取电平,整个时间片应大于60us*/
//发送一位数据,0或1
void OneWire_SendBit(unsigned char Bit)
{unsigned char i;OneWire_DQ = 1;OneWire_DQ = 0;   i = 28;     while (--i);   //总线拉低10usOneWire_DQ = Bit;    i = 138; while (--i);  //将Bit送回总线上再延时50us,检测Bit看变化赋值,比较巧妙的思想OneWire_DQ = 1;    //最终释放总线
}

发送一个字节

从低位到高位开始发送,只需要发送8次即可

发送的内容是 Byte & (0x01<<i)     i每次都++

这样就会把数据由低位到高位发送出去,在草稿纸上写一写就明白了

//发送一字节数据,从低位到高位依次发送
void OneWire_SendByte(unsigned char Byte)
{unsigned char i;for (i = 0; i < 8; i ++)OneWire_SendBit(Byte & (0x01<<i));
}

举个例子,假如要发送0x05

0x05 = 0000 0101

第一次循环 0000 0101 & 0000 0001 = 0000 0001 ≠ 0,发送1

第二次循环 0000 0101 & 0000 0010 = 0000 0000 = 0,发送0

第三次循环 0000 0101 & 0000 0100 = 0000 0100 ≠ 0,发送1

第四次循环 0000 0101 & 0000 1000 = 0000 0000 = 0,发送0

第五次循环 0000 0101 & 0001 0000 = 0000 0000 = 0,发送0

第六次循环 0000 0101 & 0010 0000 = 0000 0000 = 0,发送0

第七次循环 0000 0101 & 0100 0000 = 0000 0000 = 0,发送0

第八次循环 0000 0101 & 1000 0000 = 0000 0000 = 0,发送0

可以看到从数据由低位到高位依次发送出去了

读时序
总线控制器发起读时序时,DS18B20 仅被用来传输数据给控制器。因此,总线控制器在发出读暂存器指令[BEh]或读电源模式指令[B4H]后必须立刻开始读时序,DS18B20可以提供请求信息。除此之外,总线控制器在发出发送温度转换指令[44h]或召回 EEPROM 指令[B8h]之后读时序,详见 DS18B20 功能指令节。
所有读时序必须最少 60us,包括两个读周期间至少 1us 的恢复时间。当总线控制器把数据线从高电平拉到低电平时,读时序开始,数据线必须至少保持 1us,然后总线被释放(见图14)。在总线控制器发出读时序后,DS18B20 通过拉高或拉低总线上来传输 1 或 0。当传输逻辑 0 结束后,总线将被释放,通过上拉电阻回到上升沿状态。从 DS18B20 输出的数据在读时序的下降沿出现后 15us 内有效。因此,总线控制器在读时序开始后必须停止把 I/O 脚驱动为低电平 15us,以读取I/O 脚状态。
图 15 标识 TINIT,TRC 和 TSAMPLE 之和必须小于 15us。图 16 指出,系统时间可以用下面办法达到最大:TINIT 和 TRC 保持时间尽可能校;把控制器采样时间放到 15us 周期的最后。

接收(读)一位

主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末尾) 读取为低电平则为接收0,读取为高电平则为接收1,整个时间片应大于60us

/*接收一位主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末尾)读取为低电平则为接收0,读取为高电平则为接收1,整个时间片应大于60us*/
//接收一位数据 0或1
unsigned char OneWire_ReceiveBit(void)
{unsigned char i;unsigned char Bit;OneWire_DQ = 0;     i = 14;     while (--i);   //先把总线拉低5usOneWire_DQ = 1;     i = 14;     while (--i);   //释放总线5usBit = OneWire_DQ; //此时读取电平,数据0会把电平拉低,数据1仍然置高i = 138; while (--i);  //延时50us,满足时序要求  return Bit;
}

接收一个字节

//接收一字节数据,从低位到高位依次接收
unsigned char OneWire_ReceiveByte(void)
{unsigned Byte = 0x00;unsigned char i;for (i = 0; i < 8; i ++){//这个if判断,判断为0的时候,Byte当前位还是0,但是变量i正常++if( OneWire_ReceiveBit() )        //只有接收1才会执行下面的语句Byte |= 0x01<<i;     //从低位到高位依次取出    }return Byte;
}

举个例子,假如接收的数据是0xF0

0xF0 = 1111 0000

前四此循环,发送的数据都是0,不进入if判断,直接跳出,但是i++了,所以Byte变量后四位都是0
第五次循环 1111 0000 | 0001 0000 = 0001 0000 = 1, 发送1
第六次循环 1111 0000 | 0010 0000 = 0010 0000 = 1, 发送1
第七次循环 1111 0000 | 0100 0000 = 0100 0000 = 1, 发送1
第八次循环 1111 0000 | 1000 0000 = 1000 0000 = 1, 发送1
所以Byte变量 = 1111 0000 = 0xF0
可以看到从数据由低位到高位依次接收,验证正确


4.1.3 单总线时序代码封装

将STC15单片机 单总线底层代码封装成头文件,供给DS18B20调用

建 OneWire.c 和 OneWire.h

将4.1时序图代码整合成OneWire.c,直接复制即可

#include "OneWire.h"
#include "intrins.h"sbit OneWire_DQ = P1^4;void Delay480us()     //@11.0592MHz
{unsigned char i, j;i = 6; j = 38;do{while (--j);} while (--i);
}/*初始化主机 将总线拉低至少480us,然后释放总线,等待15~60us后,存在的 从机 会拉低总线60~240us以响应 主机之后 从机 将释放总线
*/
//单总线初始化时序
void OneWire_Init(void)
{unsigned char ackbit;unsigned char i;OneWire_DQ = 1;OneWire_DQ = 0; Delay480us();    //总线拉低480usOneWire_DQ = 1;                 //释放总线i = 138; while (--i);            //延时等待50usackbit = OneWire_DQ; Delay480us();   //读取一下是否为0,并且延时等待480us
}/*发送一位主机将总线拉低60~120us,然后释放总线,表示发送0;主机将总线拉低1~15us,然后释放总线,表示发送1。从机 将在总线拉低30us后读取电平,整个时间片应大于60us*/
//发送一位数据,0或1
void OneWire_SendBit(unsigned char Bit)
{unsigned char i;OneWire_DQ = 1;OneWire_DQ = 0;   i = 28;     while (--i);   //总线拉低10usOneWire_DQ = Bit;    i = 138; while (--i);  //将Bit送回总线上再延时50us,检测Bit看变化赋值,比较巧妙的思想OneWire_DQ = 1;    //最终释放总线
}/*接收一位主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末尾)读取为低电平则为接收0,读取为高电平则为接收1,整个时间片应大于60us*/
//接收一位数据 0或1
unsigned char OneWire_ReceiveBit(void)
{unsigned char i;unsigned char Bit;OneWire_DQ = 0;     i = 14;     while (--i);   //先把总线拉低5usOneWire_DQ = 1;     i = 14;     while (--i);   //释放总线5usBit = OneWire_DQ; //此时读取电平,数据0会把电平拉低,数据1仍然置高i = 138; while (--i);  //延时50us,满足时序要求  return Bit;
}//发送一字节数据,从低位到高位依次发送
void OneWire_SendByte(unsigned char Byte)
{unsigned char i;for (i = 0; i < 8; i ++)OneWire_SendBit(Byte & (0x01<<i));
}//接收一字节数据,从低位到高位依次接收
unsigned char OneWire_ReceiveByte(void)
{unsigned Byte = 0x00;unsigned char i;for (i = 0; i < 8; i ++){//这个if判断,判断为0的时候,Byte当前位还是0,但是变量i正常++if( OneWire_ReceiveBit() )        //只有接收1才会执行下面的语句Byte |= 0x01<<i;     //从低位到高位依次取出    }return Byte;
}

OneWire.h

#ifndef __ONEWIRE_H
#define __ONEWIRE_H#include <STC15F2K60S2.H>void OneWire_Init(void);//单总线初始化时序void OneWire_SendBit(unsigned char Bit);//发送一位数据
unsigned char OneWire_ReceiveBit(void);//接收一位数据void OneWire_SendByte(unsigned char Byte);//发送一字节数据
unsigned char OneWire_ReceiveByte(void);//接收一字节数据#endif

4.2   15单片机DS18B20代码

温度变换:初始化-->跳过ROM-->开始温度变换

温度读取:初始化-->跳过ROM-->读暂存器-->连续的读操作

具体操作看代码就明白了

建DS18B20.c

#include "DS18B20.h"#define DS18B20_SKIP_ROM           0xCC
#define DS18B20_CONVERT_T           0x44
#define DS18B20_READ_SCRATCHPAD     0xBE//温度转化:初始化-->跳过ROM-->开始温度变换
void DS18B20_ConvertT(void)
{OneWire_Init();//初始化OneWire_SendByte(DS18B20_SKIP_ROM);//跳过ROMOneWire_SendByte(DS18B20_CONVERT_T);//温度变换
}//温度读取:初始化-->跳过ROM-->读暂存器-->连续的读操作
float DS18B20_ReadT(void)
{unsigned char TMSB,TLSB;int temp;//16位数据float T;OneWire_Init();//初始化OneWire_SendByte(DS18B20_SKIP_ROM);//跳过ROMOneWire_SendByte(DS18B20_READ_SCRATCHPAD);//读暂存器 //一旦发送完指令,控制权交给 从机 TLSB = OneWire_ReceiveByte();//读的Byte0,低8位数据TMSB = OneWire_ReceiveByte();//读的Byte1,高8位数据    temp = (TMSB << 8) | TLSB;//整合数据/*温度存储格式整体左移了四位,数据扩大了16倍bit0是2的-4次幂,bit4才是2的0次幂 = 1*/T = temp / 16.0;    //强制类型转换return T;
}

温度寄存器格式

解释:

读取数据 读取低八位高八位 整合数据之后,相当于bit0 = 1,实际bit0 = 2的-4次方,所以整合之后的数据比实际数据大了16倍,所以上面的代码才有 temp/16.0

DS18B20.h

#ifndef __DS18B20_H
#define __DS18B20_H#include <STC15F2K60S2.H>
#include "OneWire.h"  //调用子头文件void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);#endif

由于转换时间比较长,更新的速率没有刷新的速率快,导致上电第一个数值是默认值25或85

如果在初始化部分先开启一次转换,延时个750ms以上,这样第一次显示的数据就不会出现默认值了

main.c 代码

#include <STC15F2K60S2.H>
#include "smg.h"
#include "DS18B20.h"
#include "OneWire.h"float T;
void main()
{   All_Init();DS18B20_ConvertT();//先转换一次,延时1s,覆盖默认值Delay_ms(1000);while(1){DS18B20_ConvertT();    //温度转换T = DS18B20_ReadT(); //温度读取SMG_ShowFloatNum(T); //数码管显示}
}

最后还有一个数码管显示浮点数的函数,手敲一个即可

smg.c

#include "smg.h"//15单片机延时函数 @11.0592MHz
void Delay_ms(int xms)
{unsigned char i, j;        while(xms--){_nop_(); _nop_(); _nop_();i = 11; j = 190;do{while (--j);} while (--i);}
}/*共阳极码表 ABCDEF都是大写*///0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F     -    灭
unsigned char NixieTable[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x80, 0xC6, 0xC0, 0x86, 0x8E, 0xBF, 0xFF, \0xC0 & 0x7F,  \0xF9 & 0x7F,  \0xA4 & 0x7F,  \0xB0 & 0x7F,  \0x99 & 0x7F,  \0x92 & 0x7F,  \0x82 & 0x7F,  \0xF8 & 0x7F,  \0x80 & 0x7F,  \0x90 & 0x7F
};//如果想显示小数点,就 &0x7F void Nixie(unsigned char location, unsigned char number)
{P2 = 0xC0;    //Y6=0;Y6C=1; 使能锁存器U8     P27 = 1; P26 = 1; P25 = 0;switch(location)//选中LED位置,位选{case 1:P0 = 0x01;break;case 2:P0 = 0x02;break;case 3:P0 = 0x04;break;case 4:P0 = 0x08;break;case 5:P0 = 0x10;break;case 6:P0 = 0x20;break;case 7:P0 = 0x40;break;case 8:P0 = 0x80;break;}P2 = 0xFF;  //Y7=0;Y7C=1; 使能锁存器U7     P27 = 1; P26 = 1; P25 = 1;P0=NixieTable[number];//数字Delay_ms(1);P0=0xFF;//消影清零
}/*数码管显示浮点数,支持0-1000以内的浮点数*/
void SMG_ShowFloatNum(float num)
{unsigned char Sep_Num[8]; //一次存放 千百十个...long temp;if (num >= 0)    //正数temp = (long)(num*1000);       else    temp = (long)(-num*1000);Sep_Num[0] = temp / 1000000 % 10;    //千位Sep_Num[1] = temp / 100000  % 10;  //百位Sep_Num[2] = temp / 10000   % 10;  //十位Sep_Num[3] = temp / 1000    % 10;  //个位Sep_Num[4] = temp / 100     % 10;  //小数点后第一位Sep_Num[5] = temp / 10      % 10; //小数点后第二位Sep_Num[6] = temp             % 10;   //小数点后第三位   Nixie(4, Sep_Num[3] + 18); //下标+18代表显示小数点Nixie(5, Sep_Num[4]);Nixie(6, Sep_Num[5]);Nixie(7, Sep_Num[6]);if        (num >=10     && num < 100  ) {Nixie(3, Sep_Num[2]);}    //显示十位else if (num >=100    && num < 1000 ) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]);}    //显示十位百位else if (num >=1000   && num <= 9999) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]); Nixie(1, Sep_Num[0]);}   //显示十位百位千位else if (num > -100   && num <= -10 ) {Nixie(3, Sep_Num[2]); Nixie(2,16);} //显示十位,并且显示负号else if (num > -1000  && num <= -100) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]); Nixie(1,16);} //显示十位百位,并且显示负号else if (num >= -9999 && num <=-1000) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]); Nixie(1, Sep_Num[0]);} //显示十位百位千位,但是数码管不够了后续想显示出来,就把数码管显示的内容整体往后挪动一个位置即可else if (num > -10    && num < 0    ) {Nixie(3,16);}   //大于-10小于0的负数
}       //关闭 蜂鸣器继电器LED数码管
void All_Init(void)
{P2 = 0xA0;    // 1010 0000P0 = 0x00; //off蜂鸣器继电器P2 = 0x80;  // 1000 0000P0 = 0xFF; //offLEDP2 = 0xC0; //使能锁存器U8 1100 0000P0 = 0xFF;  //选择所有数码管P2 = 0xFF;    //使能锁存器U7 1111 1111P0 = 0xFF;  //关闭所有数码管
}

smg.h

#ifndef __SMG_H__
#define __SMG_H__#include <STC15F2K60S2.H>
#include "intrins.h"extern unsigned char NixieTable[];void Delay_ms(int xms); //15单片机延时函数 @11.0592MHzvoid All_Init(void);    //关闭 蜂鸣器继电器LED数码管void Nixie(unsigned char location, unsigned char number);void SMG_ShowFloatNum(float num);//void SMG_ShowFloat(float num);#endif

4.3   51单片机DS18B20代码

51单片机的代码和15单片机代码逻辑是一致的,只有延时时间代码不同

单总线底层代码

DS18B20 需要严格的单总线协议以确保数据的完整性

在这个底层代码中初始化发送一位读取一位的函数都有一些相同的改动

即在函数开头写EA = 0; 函数结尾写EA = 1;

这样程序就不会被中断打断了,能保证数据完整!

上面15单片机的代码也可以加这两句

#include <REGX52.H>
#include "OneWire.h"sbit OneWire_DQ = P3^7;      //端口/*初始化主机 将总线拉低至少480us,然后释放总线,等待15~60us后,存在的 从机 会拉低总线60~240us以响应 主机之后 从机 将释放总线   */
//单总线
unsigned char OneWire_Init(void)
{unsigned char i;unsigned char AckBit;EA = 0;  OneWire_DQ = 1;    //先给总线置1OneWire_DQ = 0;    //再拉低总线i = 230; while (--i);   //延时500us(至少拉低总线480us)OneWire_DQ = 1;            //然后释放总线i = 32; while (--i);   //延时70usAckBit = OneWire_DQ;   //读出I/O口电平,存放在AckBiti = 230; while (--i);   //延时500us(也是至少480us)EA = 1;  return AckBit;
}/*发送一位主机将总线拉低60~120us,然后释放总线,表示发送0;主机将总线拉低1~15us,然后释放总线,表示发送1。从机 将在总线拉低30us后读取电平,整个时间片应大于60us*/
void OneWire_SendBit(unsigned char Bit)
{   unsigned char i;EA = 0;    OneWire_DQ = 0;            //先直接拉低,初始化之后总线是1,i = 4;    while (--i);    //延时10usOneWire_DQ = Bit;      //10us后将Bit送回总线i = 23; while (--i);    //延时50usOneWire_DQ = 1;            //最后释放总线EA = 1;
}/*接收一位主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末尾)读取为低电平则为接收0,读取为高电平则为接收1,整个时间片应大于60us  */
unsigned char OneWire_ReceiveBit(void)
{unsigned char i;unsigned char Bit;EA = 0;OneWire_DQ = 0;         //主机将总线拉低1~15usi = 2;  while (--i);    //延时5usOneWire_DQ = 1;         //释放总线i = 2;   while (--i);    //延时5usBit = OneWire_DQ;       //采样、读取电平(读取到0就是从机给拉低了)i = 23;   while (--i);    //延时50us//结束后 从机 会自动释放总线 EA = 1;   return Bit;
}//发送一个字节
void OneWire_SendByte(unsigned char Byte)
{   unsigned char i;for(i=0;i<8;i++){OneWire_SendBit(Byte&(0x01<<i));}
}//接收一个字节
unsigned char OneWire_ReceiveByte(void)
{unsigned char i;unsigned char Byte = 0x00;for(i=0;i<8;i++){if(OneWire_ReceiveBit()) {Byte |= (0x01<<i);} //从低位到高位依次取出//这个if判断,判断为0的时候,Byte当前位还是0}return Byte;
}
#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__unsigned char OneWire_Init(void);
void OneWire_SendBit(unsigned char Bit);
unsigned char OneWire_ReceiveBit(void);
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte(void);#endif

DS18B20代码

#include <REGX52.H>
#include "OneWire.h"
//#include "LCD1602.h"#define DS18B20_SKIP_ROM            0xCC
#define DS18B20_CONVERT_T           0x44
#define DS18B20_READ_SCRATCHPAD     0xBE//温度变换:初始化-->跳过ROM-->开始温度变换
void DS18B20_ConvertT(void)
{OneWire_Init();//初始化OneWire_SendByte(DS18B20_SKIP_ROM);//跳过ROMOneWire_SendByte(DS18B20_CONVERT_T);//温度变换
}//温度读取:初始化-->跳过ROM-->读暂存器-->连续的读操作
float DS18B20_ReadT(void)//温度读取
{   unsigned char TLSB,TMSB;int temp;//16位数据float T;OneWire_Init();OneWire_SendByte(DS18B20_SKIP_ROM);OneWire_SendByte(DS18B20_READ_SCRATCHPAD);//读暂存器//一旦发送完指令,控制权交给 从机 TLSB = OneWire_ReceiveByte();  //读的Byte0,低8位数据TMSB = OneWire_ReceiveByte();   //读的Byte1,高8位数据//用LCD1602显示出来这16位二进制数(后四位是小数,再前边四位是整数部分)
//  LCD_ShowBinNum(1,1,TMSB,8);
//  LCD_ShowBinNum(1,9,TLSB,8);temp = (TMSB << 8) | TLSB;        //正好为int类型16位数据/*温度存储格式整体左移了四位,数据扩大了16倍bit0是2的-4次幂,bit4才是2的0次幂 = 1*/T = temp/16.0;  //强制类型转换return T;
}

中间注释掉两行,可以用LCD1602显示温度读取到的16位数据

#ifndef __DS18B20_H__
#define __DS18B20_H__void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);//温度读取#endif

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "OneWire.h"
#include "DS18B20.h"//char ack;
float T;    //全局变量void main()
{DS18B20_ConvertT();    //先转换1次,Delay(1000);     //再延时1s,就不会显示默认温度25了LCD_Init();
//  LCD_ShowString(1,1,"Temperature:");
//  ack = OneWire_Init();
//  LCD_ShowNum(2,1,ack,3);LCD_ShowChar(2,9,0xDF);LCD_ShowChar(2,10,'C');while(1){        DS18B20_ConvertT();T = DS18B20_ReadT();if(T<0){LCD_ShowChar(2,1,'-');//显示个负号T=-T;    //转化成正数}else {LCD_ShowChar(2,1,'+');}LCD_ShowNum(2,2,T,3);//整数部分LCD_ShowChar(2,5,'.');LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,3);//乘一万,小数部分移动到整数部分,再取余,再强制类型转换unsigned long}}

内容有点多呀,再敲敲吧~


学习视频链接

DS18B20温度读取

51单片机15单片机 温度传感器DS18B20相关推荐

  1. 51单片机15单片机 时钟芯片DS1302

    目录 前言 一.DS18B20芯片介绍 二.芯片引脚定义与应用电路 三.寄存器定义 四.命令字 五.数据流 六.时序图与数据读写 6.1 单字节写(Write) 6.2 单字节读(Read) 6.3 ...

  2. 51单片机温度传感器DS18B20

    51单片机温度传感器DS18B20 实现功能 插上DS18B20温度传感器,数码管显示检测的温度值 单片机型号:STC89C52 DS18B20介绍 1.DS18B20简介 DS18B20 是由 DA ...

  3. AutoLeaders控制组——51单片机学习笔记(DS18B20温度传感器、LCD1602、直流电机+PWM)

    本篇内容是观看B站江科大自化协UP主的教学视频所做的笔记,对其中内容有所引用,并结合自己的单片机板块进行了更改调整. 以下笔记内容以一个视频为一个片段(内容较多,可能不适合速食,望见谅) 一些内容涉及 ...

  4. 基于51单片机ds1302时钟、ds18b20、lcd12864的恒温器

    目录 项目:基于51单片机ds1302时钟.ds18b20的恒温器 功能说明: 运行流程: 效果展示: 供电方式: 用途: 提高: 附: ​                              ...

  5. 【蓝桥杯单片机11】单总线温度传感器DS18B20的基本操作

    [蓝桥杯单片机11]单总线温度传感器DS18B20的基本操作 广东职业技术学院 欧浩源 单总线数字温度传感器DS18B20几乎成了各类单片机甚至ARM实验板的标配模块来,在蓝桥杯的往届省赛和国赛中,这 ...

  6. 基于51单片机的数字温度计ds18b20温度测量报警仿真(仿真+源码+全套资料)

     资料编号:074 可以设置最低值和最高值,超过上限值LED1亮,超过下限值,LED2亮,LCD1602显示 全套资料齐全:具体请看下方演示视频 74-基于51单片机的数字温度计ds18b20温度测量 ...

  7. 15单片机通过WIFI模块ESP8266实现手机远程监控可燃气体浓度

    15单片机通过WIFI模块ESP8266实现手机远程监控可燃气体浓度 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 一,系统方案 1.方案描 ...

  8. 国信长天单片机竞赛训练之DS18B20温度报警实验(三)

    目标要求:通过板载的DS18B20获取温度,并在数码管上保留4位小数显示,温度超过25.0000度,蜂鸣器报警:低于等于25.0000度,所有LED间隔2秒闪烁:温度超过25.0000度,通过串口发送 ...

  9. 【单片机】单片机各系列(51,PIC,AVR,MSP430/432,ARM)介绍

    文章目录 说明 资料一 ······ 综述 资料二 ······ 综述 资料三 ······ MSP430 资料四 ······ 综述 资料五 ······ 合集 说明   因为近期想要了解各种单片机 ...

最新文章

  1. ngnix编译遇到的问题.
  2. 一文详解目标跟踪中的相关滤波
  3. 20145234黄斐《Java程序设计》第十周
  4. Filezilla-使用ssh连接到服务器-上传下载文件
  5. [HNOI 2011]卡农
  6. 【Python】常用的数据类型介绍以及它们之间相互转化
  7. Python中的一些小语法
  8. 习题3.4 最长连续递增子序列 (20 分) 数据结构 PTA
  9. C及C++中的一些基础知识点(持续更新)
  10. Android小知识- LayoutInflater
  11. 数据集-知识图谱:FreeBase(通用知识图谱)【英文】
  12. html embed用法
  13. SpringBoot apple苹果支付回调验证
  14. unity使用tiled文件,将数据用unity打开,可以无限tiled地图
  15. 如何启用计算机睡眠功能,如何让电脑休眠_如何开启电脑休眠模式-win7之家
  16. VM Ware安装CentOS 7
  17. 教你玩 Robocode(2) —— 使用Eclipse开发Robot
  18. 爬虫 人人车字体反爬分析(含源码)
  19. 查看执行计划 db2expln 使用说明
  20. linux脚本文件编辑器,Shell文件编辑器

热门文章

  1. 用库卡机器人编程写字_KUKA机器人的操作与基本运动编程(学员必备)
  2. 关于鼠标右键的快捷键
  3. 客户端访问https时应无浏览器(含终端)安全警告信息;_Http升级Https(Let#x27;s Encrypt)...
  4. char与varchar的区别?
  5. 计算机基础知识截屏,电脑截屏技巧 截图快捷键是什么
  6. 蚁群算法解决多峰函数优化问题
  7. java常见的5个异常_java常见的5种异常举例
  8. Python—实现语音自动播报最新疫情信息
  9. java截取视频片段_使用javacv 截取视频指定帧节
  10. 连接不上oracle数据库