1、DS18B20简介

DS18B20本身就是一个温度传感器,只需要将DS18B20的数据引脚和单片机的一个I/O口接上,单片机通过1-Wire协议与DS18B20进行通信,读出温度。

CT107D开发板相关模块电路图如下:
在这里插入图片描述

2、DS18B20的温度转换规则

DS18B20可以直接读出数字的温度数值。温度传感器的精度为用户可编程的9、10、11或12位,分别以0.5℃,0.25℃,0.125℃和0.0625℃增量递增。在上电状态下默认精度为12位。也就是温度每变化0.0625度,二进制数字变化1。转换的精度由配置寄存器决定,如下:(R1R0出厂默认11)

在这里插入图片描述

DS18B20启动后保持低功耗等待状态,当需要执行温度测量和AD转换时,总线控制器必须发出[44h]命令,启动温度转换,即Write18b20(0x44)。转换完以后,产生的温度数据以两个字节的形式被存储到 高速暂存器 的温度寄存器中(先低后高),DS18b20继续保持等待状态。

DS18B20的温度数据格式如下,转化后得到12位数据,存储在DS18B20的两个8位的RAM中。MSB里面存储的是高字节,LSB里面存储的是低字节。 高字节的前5位是符号位,如果测得的温度大于0,这5位为‘0’,只要将测到的数值乘以0.0625即可得到实际温度;如果温度小于0,这5位为‘1’,测到的数值需要先减1再取反再乘以0.0625即可得到实际温度。

在这里插入图片描述
温度/数据关系转换表如下:

在这里插入图片描述

3、ROM & RAM操作指令

(1)ROM指令表
指令 约定代码 功能
Read ROM 33H 读DS18B20温度传感器ROM的编码,即64位地址
Match ROM 55H 后跟64位ROM序列,让总线控制器在多点总线上匹配某一特定的DS18B20。匹配后的从机才能响应后续命令,其余不匹配的从机等待复位脉冲。总线上有单个或多个器件时都可使用该命令。
Skip ROM CCH 当只有一个从机时,忽略64位ROM地址,直接向DS18B20发出温度转换命令
Search ROM F0H 用于确定挂在同一总线上DS18B20的个数和识别64位ROM地址,为操作各器件做准备。
Alarm ROM ECH 执行后,温度超过上限或下限的片子做出响应。

当我们只挂了一个DS18B20时,只需要写一条关于ROM的指令,即Write18b20(0xcc);

(2)RAM指令表
指令 约定代码 功能
启动温度转换(Convert T) 44H 启动DS18B20进行温度转换,从转换到获取温度的时间取决于DS18B20的精度,12位转换最长750ms,结果存入9字节RAM。
读暂存器 BEH 读9字节RAM的内容
写暂存器 4EH 发出向内部RAM的3、4字节写上、下限温度数据命令,后面紧跟着传送两字节数据
复制暂存器 48H 将RAM中第3、4字节的内容复制到EEPROM中
重调E2PROM B8H 将EEPROM内容恢复到RAM中的3、4字节
读供电方式 B4H 读DS18B20的供电模式,寄生供电时DS18B20发送“0”,外接电源供电时DS18B20发送“1”。

4、通过单线总线端口访问DS18B20过程

(1)初始化

类似于I2C的寻址,1-Wire总线开始也需要检测这条总线上是否存在DS18B20这个器件。如果存在,总线会根据时序要求返回一个低电平;如果不存在,则不返回,即总线保持高电平。该过程称为检测存在脉冲

获取存在脉冲有两个作用:①检测是否存在DS18B20 ②通过这个过程通知DS18B20做准备,单片机要对它进行操作。

检测存在脉冲的时序图如下:
在这里插入图片描述
整个过程描述如下:①单片机拉低这个引脚,持续480~960us (以持续500us为例) ②单片机释放总线,即拉高电平。 ③15 ~60us后,如果DS18B20这个器件存在,就会主动拉低这个引脚,返回一个低脉冲(为了确保读到这个脉冲,选择延时60us,但不能超过75us)④持续60 ~240us后,DS18B20释放总线,I0端口被上拉电阻拉高。

对应的程序如下:

//软件延时函数,延时时间为(t*10)us
void DelayX10us(u8 t)
{
	do{
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		} while(--t);
}

bit Init_18b20()
{
	bit initflag;
	EA = 0;
	DQ = 0;         //读写之前都要将该引脚拉低
	DelayX10us(50); //延时500us
	DQ = 1;
	DelayX10us(6);  //延时60us
	initflag = DQ;  //读取存在脉冲,0存在,1不存在
	while(!DQ);     //等待存在脉冲结束,即DQ = 1
	EA = 1;         //打开使能总中断
	
	return initflag;	
}

注:需要说明的是,DS18B20对时序的要求非常严格,所以在开始对某一位操作前要先关闭中断,防止中途受到干扰。但是位与位之间的间隔是可以无穷大的,完全可以在完成一位的操作之后,去干别的事情,结束之后再回来操作下一位。

(2)ROM操作指令

先只学习一条总线上只接一个器件的情况,此时只需要直接跳过ROM,不进行ROM检测。用到的语句如下:

Write18b20(0xcc);//跳过ROM操作
(3)RAM操作指令

常用到的两条如下:

Write18b20(0x44);//启动一次温度转换
Write18b20(0xbe);//发送读指令
(4)DS18b20的位写时序

DS18b20的位写入时序

在这里插入图片描述
过程描述如下:在给DS18b20写数据之前,单片机要先把引脚拉低,持续一段时间(程序中是两个_nop_),而后DS18b20会在60秒之内读完这位数据。然后释放总线(拉高引脚)

代码如下:

//向DS18B20写入一个字节,dat为待写入字节
void Write18b20(u8 dat)
{
	u8 i;
	EA = 0;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		_nop_();         //产生2us低电平脉冲
		_nop_();
		DQ = dat & 0x01; //先读取的是低位	
		DelayX10us(6);
		dat>>=1;         //次低位移到最低位,等待读取
		DQ = 1;
	}
	EA = 1;
}
(5)DS18b20的位读时序

DS18b20的位读时序图如下:

在这里插入图片描述
过程描述如下:在读取DS18B20数据之前,单片机首先要拉低这个引脚,并且至少保持1us。而后释放这个引脚(拉高电平),尽快读取。从拉低这个引脚到读取不能超过15us。再延时60us,确保读取完毕。

代码如下:

//从DS18B20读取一个字节,返回值为读到的字节
u8 Read18b20()
{
	u8 i,dat;
	EA = 0;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		_nop_();
		_nop_();
		DQ = 1;
		_nop_();
		_nop_();
		dat >>= 1;
		if(DQ == 1)
		{
			dat |= 0x80;//先读的是低位,依次右移
		}
		DelayX10us(6);
	}
	EA = 1;
	return dat;
}

5、ds18b20.h + ds18b20.c

ds18b20.h

#ifndef __DS18B20_H
#define __DS18B20_H

#include "system.h"

sbit DQ = P1^4;

void DelayX10us(u8 t);
bit Init_18b20();
void Write18b20(u8 dat);
u8 Read18b20();
bit Start18b20();
u8 TempGet();


#endif

ds18b20.c

#include "ds18b20.h"
#include "intrins.h"

//软件延时函数,延时时间为(t*10)us
void DelayX10us(u8 t)
{
	do{
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
	}while(--t);
}
 

bit Init_18b20()
{
	bit initflag;
	EA = 1;
	DQ = 0;         //读写之前都要将该引脚拉低
	DelayX10us(50); //延时500us
	DQ = 1;
	DelayX10us(6);  //延时60us
	initflag = DQ;  //读取存在脉冲,0存在,1不存在
	while(!DQ);     //等待存在脉冲结束,即DQ = 1
	EA = 1;         //打开使能总中断
	
	return initflag;	
}

//向DS18B20写入一个字节,dat为待写入字节
void Write18b20(u8 dat)
{
	u8 i;
	EA = 0;
	for(i=0;i<8;i++)      //低位在前,逐位移除
	{
		DQ = 0;
		_nop_();          //产生2us低电平脉冲
		_nop_();
		DQ = dat & 0x01;  //先读取低位	
		DelayX10us(6);
		dat>>=1;
		DQ = 1;
	}
	EA = 1;
}

//从DS18B20读取一个字节,返回值为读到的字节
u8 Read18b20()
{
	u8 i,dat;
	EA = 0;
	for(i=0;i<8;i++)  //低位在前,诸位读取
	{
		DQ = 0;
		_nop_();
		_nop_();
		DQ = 1;
		_nop_();
		_nop_();
		dat >>= 1;
		if(DQ == 1)
		{
			dat |= 0x80;//先读的是低位,依次右移
		}
		DelayX10us(6);
	}
	EA = 1;
	return dat;
}

bit Start18b20()
{
	bit ack;
	ack = Init_18b20();   //执行总线复位,获取18b20的应答
	if(ack == 0)          //如果18B20应答正确,启动一次转换
	{
		Write18b20(0xcc); //跳过RAM操作
		Write18b20(0x44); //启动一次温度转换
	}
	return ~ack;          //ack == 0表示操作成功,返回值对其取反
}

u8 TempGet()
{
	bit ack;
	u8 LSB,MSB,temp;
	ack = Init_18b20();   //执行总线复位,获取18b20的应答
	if(ack == 0)          //如果18B20应答正确,启动一次转换
	{
		Write18b20(0xcc); //跳过RAM操作
		Write18b20(0xbe); //发送读命令
		LSB = Read18b20();
		MSB = Read18b20();
		temp = (MSB<<4)|(LSB>>4);		
	}
	return temp;
	
}

前一篇: 单片机学习(11)——实时时钟DS1302

下一篇: 【蓝桥杯】单片机学习(13)——AD模数转换及PCF8591

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐