51单片机-18B20温度传感器

目录

一.18B20组成

1.64位ROM

2.内部存储器

3.配置寄存器

二.18B20温度转换规则及指令 

三.18B20指令时序图及代码实现

1.18B20初始化

2.18B20读时序

3.18B20写时序

 四.51单片机具体实现代码

1.18B20D读取数据函数

2.18B20D读取数据函数的头文件 

3.主函数



一.18B20组成

  • 管脚顺序:1-GND 2-DQ 3-VDD
  • 组成:64位ROM +存储器和控制器 +高速缓存存储器 + 8位CRC生成器 + 温度灵敏元件 + 高/低温触发器TH/TL + 配置寄存器

1.64位ROM

出厂前已经刻录好数据,用于存储18B20的地址序列号,由 8位产品类型标号 + 48位序列号 + 8位CRC循环冗余校验码。

用处:用于实现一根总线挂载多个18B20

2.内部存储器

内部存储器包括高度暂存器RAM + EEPROM;

EEPROM用于存放TH/TL高低温触发器+结构寄存器

3.配置寄存器

存储的第四字节为配置寄存器,用于配置传感器的精度;组成 1111 1+ R0 + R1 + 0 ,低4位和第7位不可改变。

R1R0精度
009bit
0110bit
1011bit
1112bit

二.18B20温度转换规则及指令 

  • 核心功能:可直接读出数字的温度数值
  • 精度:用户可编程 9位 --0.5℃;10位 --0.25℃;11位 --0.125℃;12位 --0.0625℃。默认精度:12位
  • 工作过程:总线发出44H命令,进行测量温度和AD转换;转换后,产生数据以两字节的形式存储在高速缓存存储器中后,器件保持等待状态。
  • 温度数据组成:16位,
    • (MS 5bit)高5位为符号位,T>0时,全为0,实际温度 = 后7位数据 *1 ℃ + 后4位数据* 0.625℃;T<0时,全为1,实际温度 =( 后7位数据取反+1的数据前7位)* 1℃ +( 后4位数据取反+1的数据前7位)* 0.0625℃;
    • (MS 3bit+ LS 4bit)高字节的后三位+低字节的前4位为整数部分
    • (LS 4bit)低字节的后4位为小数部分
    • eg:
      • 1111 1111  1111 1000 (FFF8h)>>> 1111 1 温度为负 ,111 1111  1000取反+1 =000 0000 1000(8) ;实际的温度 = -8*0.0625 = 0.5℃
      • 0000 0111 1101 1000 (07D8h)>>> 0000 0 温度为正 ,0000 0111 1101 1000  ;实际的温度 =  (111 1101)125  * 1 +(1000)8 * 0.0625= 125 .5℃

三.18B20指令时序图及代码实现

ROM指令表
指令代码功能
读ROM33H读取ROM的序列号
跳过ROMCCH忽略64bitROM地址,直接可进行温度转换
温度转换44H启动温度转换,转换时长最大750ms,存入内部RAM
读暂存器0BEH读取内部RAM的内容

1.18B20初始化

初始化时序
  1. 数据线拉0
  2. 延时480-960us
  3. 数据线拉1
  4. 延时80us,初始化成功15-60us内返回0,因为不可以无限等待,需要进行超时判断
  5. 延时,时间长度从数据线拉1算起不少于480us
unsigened char TempInit()       //判断温度传感器是否存在
{
	unsigened char i = 0;
	DsPort = 0;                //数据线拉0
	i = 70;                    //延时480-960us
	while(i--);                //实际延时642us
	
	DsPort = 1;                //拉高后延时等待80us,判断DS是否响应,响应数据线会被再次拉低
	
	i=0;
	while(DsPort)              //判断DS是否响应,拉低数据线
	{
		Delay1ms(1);
		i++;
		if(i>5)
		{
			return 0;         //判断超时,温度传感器为不存在
		}
		
	
	}
	
	return 1;                 //温度传感器存在
	
	
}

2.18B20读时序

读时序

1.数据线拉0

2.延时4us

3.数据线拉1,释放总线准备读取数据

4.延时10us

5.读取数据线的1bit数据,进行数据处理

6.延时45us

7.重复以上步骤,读完1Byte

unsigned char Ds18b20ReadByte()     //读取数据
{
	unsigned char i,j,bi,rdat;
	
	rdat = 0;
	for(j=8;j>0;j--)
	{
		DsPort = 0;            //1.数据线拉低 2.延时15us 3.数据线拉高,释放总线,准备读数据 
							   //4.延时10us 5.读数据的状态,进行数据处理 6.延时45us
		i++;                   //延时
		
		DsPort = 1;            //数据线拉高
		
 		i++;                   //延时
		i++;
		
		bi = DsPort;           //读取1bit数据,储存数据
		rdat = ( rdat >> 1 ) | (bi << 7 );    //bi  = 1,    1000 0000 | 000000 = 1000 0000
		
		i = 4;
		while(i--);             //延时>45us
		
	}
	return rdat;
}

3.18B20写时序

写时序

1.数据拉0

2.延时15us

3.按低位>>高位顺序发送数据(一次1位)

4.延时60us

5.数据线拉1

6.重复以上步骤,发完1Byte数据

7.数据线拉1,总线释放 

void Ds18b20WriteByte(unsigned char dat)
{
	unsigned  i,j;
	for(j=0;j<8;j++)
	{
		DsPort = 0;           //1.数据线拉低 2.延时15us 3.发送数据,低位到高位 4.延时60u 5.数据线拉高
		i++;                  //延时15us
		DsPort = dat & 0x01;  //发送数据
		
		i=6; 
		while(i--);           //延时68us
		
		DsPort =1;            //数据线拉高
		
		dat >>= 1;            //右移一位,发送下一位
		
	
	}
	

}

 四.51单片机具体实现代码

1.18B20D读取数据函数

/********************
 *18B20D读取数据函数 *
 *                  *
 ********************/

#include "temp.h"                     //加载头文件

void Delay1ms(uint y)                 //延时yms函数
{
	uint x=100;
	for(;y>0;y--)
	{
		for(x=110;x>0;x--);
		
	
	}

}



uchar TempInit()       //18B20初始化,判断温度传感器是否存在
{
	uchar i = 0;
	DsPort = 0;        //数据线拉0
	i = 70;            //延时480-960us
	while(i--);        //实际延时642us
	
	DsPort = 1;        //拉高后延时等待80us,判断DS是否响应,响应数据线会被再次拉低
	
	i=0;
	while(DsPort)      //判断DS是否响应,拉低数据线
	{
		Delay1ms(1);
		i++;
		if(i>5)
		{
			return 0;    //判断超时,温度传感器为不存在
		}
		
	
	}
	
	return 1;           //温度传感器存在
	
	
}


void Ds18b20WriteByte(uchar dat)   //写入数据操作
{
	uchar i,j;
	for(j=0;j<8;j++)
	{
		DsPort = 0;           //1.数据线拉低 2.延时15us 3.发送数据,低位到高位 4.延时60u 5.数据线拉高
		i++;                  //延时15us
		DsPort = dat & 0x01;  //发送数据
		
		i=6; 
		while(i--);           //延时68us
		
		DsPort =1;            //数据线拉高
		
		dat >>= 1;            //右移一位,发送下一位
		
	
	}
	

}


uchar Ds18b20ReadByte()        //读取数据操作
{
	uchar i,j,bi,rdat;
	
	rdat = 0;
	for(j=8;j>0;j--)
	{
		DsPort = 0;            //1.数据线拉低 2.延时15us 3.数据线拉高,释放总线,准备读数据 
									  //4.延时10us 5.读数据的状态,进行数据处理 6.延时45us
		i++;                   //延时
		
		DsPort = 1;            //数据线拉高
		
 		i++;                   //延时
		i++;
		
		bi = DsPort;
		rdat = ( rdat >> 1 ) | (bi << 7 );    //bi  = 1,    1000 0000 | 000000 = 1000 0000
		
		i = 4;
		while(i--);             //延时>45us
		
	}
	return rdat;
}

void ChangeTemp()             //温度转换
{
	TempInit();                //器件初始化
	Delay1ms(1);               //延时
	Ds18b20WriteByte(0xCC);    //CC为跳过ROM,直接可以温度转换
	Ds18b20WriteByte(0x44);    //44为启动温度转换,一次需要750ms,连续检测可以不进行延时
	
	

}

void ReadTempCom()             //温度读取指令
{
	TempInit();                //器件初始化
	Delay1ms(1);               //延时
	Ds18b20WriteByte(0xCC);    //CC为跳过ROM,直接可以温度转换
	Ds18b20WriteByte(0xBE);    //BE为读取ROM的数据,两个字节
	


}	

int ReadTemp()                 //封装函数,读取温度
{
	int temp = 0;              
	uchar tmh,tml;             //存储温度高/低字节
	ChangeTemp();              //温度转换
	ReadTempCom();             //温度读取
	tml = Ds18b20ReadByte();   //ROM的低字节
	tmh = Ds18b20ReadByte();   //ROM的高字节
	temp = tmh;                //存储高字节    
	temp <<= 8;               
	temp |= tml;               //存储低字节
	return temp;
}	
	
	
	

2.18B20D读取数据函数的头文件 

/****************************
 *18B20D读取数据函数的头文件 *
 *                          *
 ****************************/
#ifndef _temp_H
#define _temp_H

#include <reg52.h>

#ifndef uchar 
#define uchar unsigned char	
#endif

#ifndef uint 
#define uint unsigned int	
#endif


int ReadTemp();



sbit DsPort =  P3^7;

#endif

3.主函数

/*
DS18B20 温度传感器,1 GND 2 DATA 3 VDD
组成:
1. 64bit光刻ROM 是 B20的地址序列号: 28H 类型 + 48bit 序列号 + RCR循环冗余校验(8bit)

2. 精度可编程 9/10/11/12位,0.5/0.25/0.125/0.0625℃,默认12位

3. 工作过程:等待 >>> MUC 发送44H  >>>  器件进行温度测量和AD转换 >>> 数据存储再温度寄存器(2字节/16bit)
	>>> 等待

4  温度寄存器组成:MS + LS , 
	MS的前5为符号位,T>0, 全为0 /  T<0,全为1,且后面的数据需要取反加1  
	MS 3bit + LS 高4bit 为整数,转换为温度时只需要乘以1℃
	LS 低4bit 为小数,转换为温度时只需要乘以0.0625      1000  =  8*0.0625 =0.5 摄氏度
	eg:0000 0111 1101 1000  >>>>  125.5℃


*/
#include "reg52.h"
#include "temp.h"

typedef unsigned char u8;
typedef unsigned int u16;


sbit LSA = P2^2;           //数码管选通
sbit LSB = P2^3;
sbit LSC = P2^4;

u8 code smgduan[] = {0x3f, 0x06, 0x5b, 0x4f,
                     0x66, 0x6d, 0x7d, 0x07,
                     0x7f, 0x6f, 0x77, 0x7c, 
                     0x39, 0x5e, 0x79, 0x71};         
                            //数据管0-F显示
u8 disp[4];                 //数码管数据
u8 num;
int read;


void delay(u16 i)           //延时函数
{
	while(i--);

}



void datapros(int temp)                          //对读取18B20的数据进行处理
{
	float tp;                                    //暂时存储温度数据 
	read = temp;                                 //用于串口通讯读取

	if(temp<0)                                   //温度小于0,需要取反+1;补码;我们还原时需要-1,取反
	{
		disp[0] = 0x40;                          //显示负号
		temp = ~(temp-1);                        //数据还原,-1 ,取反
		tp = temp;
		temp = tp * 0.0625 * 100 + 0.5;          //温度的精度0.0625,乘以100用于保留小数后两位,同时将float转为int;0.5用于进位
		
	}

	else                                          //温度>0
	{
		disp[0] = 0x00;                           //符号位显示
		
		tp = temp;
		temp = tp * 0.0625 * 100 + 0.5;
		
		
	}
	
	disp[1] = smgduan[temp / 10000];             //除10000的目的时,之前将temp*100,这边返            
回,然后取百分位 
	disp[2] = smgduan[temp % 10000 / 1000];      //十位
	disp[3] = smgduan[temp % 10000 %1000 / 100] | 0x80;  
												 //个位+小数点
	disp[4] = smgduan[temp %100 / 10 ];          //小数第一位
	disp[5] = smgduan[temp %100 % 10];           //小数第二位
	
}

void DigDisplay()                                //数码管显示函数
{
	u8 i;
	for(i= 0; i<6;i++)                           //对6个8位数码管进行循环扫描
	{
		LSA = i % 2;             
		LSB = i / 2 % 2;
		LSC = i / 4 % 2;
		
		P0 = disp[i];
		delay(100);
		P0 = 0X00;                               //消影
		}
		
}


void UsartInit()     //串口通讯初始化
{
	TMOD |= 0X20;    //TMOD ,低四位控制T0,GATE,C/~T ,M1 ,M0 ===>  C/T=0定时器模式, M1,M0 = 1 0 模式2,8位定时器自动重装载,,GATE = 0软件控制定时器 =1是使用外部中断
                     //使用|=运算,是为了不影响前面位	
	
	TH1 = 0XF3;      //设置定时器,用于输出波特率,设置波特率初值,对应的是4800, 波特率 = 2^smod * f / 32 /(12* (2^8-X))》》》
	TL1 = 0XF3;		 // X = 256 - 32 * 12 * 波特率 / 2^smod / f 
	
	PCON = 0X80;     //SMOD 用于倍频 ,但是不可以位寻址,所以需要对所在的PCON设置
	
	TR1 = 1;         //开启定时器1
	
	
	SCON =0X50;      //串行通讯控制  0101 0000  SM0 SM1 SM2(多机通讯) REN(串口接收允许位) TB8 RB8 TI RI(接收中断标志位);工作方式1:1帧10位
	
	ES = 1;          //中断使能
	EA = 1;

}

void main()          //主函数
{
	
	UsartInit();     
	
	while(1)
	{
		
		datapros(ReadTemp());
		
		DigDisplay();
		
		
	}





}


void Usart() interrupt 4 
{
    u8 i,byte;
    int a ;               //int只占据两个字节
    
    //u8 recData = SBUF;  //读取缓存寄存器的数据,RI=1(中断标志位)进入中断
    RI = 0;               //需要手动清零
    a = read;             
    //SBUF = recData;
    for(i = 0; i < sizeof(a); i++) //循环发送两个字节
    {
        byte = (a >> (i * 8)) & 0xFF;
        SBUF = byte;               //把收到数据发送出去
        while(!TI);                //等待发送结束
        TI = 0;
    }
}

	
	
	
	
	




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值