DS18B20温度传感器-1总线通信

写的不知道好很差,有什么不对的地方还请指出,谢了。算法

一、本节基于DS18B20 1总线通信。函数

二、驱动DS18B20,代码3个:初始化DS18B20、写1字节、读1字节。编码

三、运用DS18B20,接口有7个:读取ROM编码、配置高温报警低温报警及精度、温度转换、拷贝寄存器值到EEPROM、召回EEPROM值到寄存器里、读取DS18B20的状态(好像没有什么用)、读取DS18B20的温度(float类型,精度自行选择)。spa

四、温度读取出来后用数码管来显示小数,目前数码管显示小数有点小问题。这个问题之后在解决。code

五、DS18B20对时序有要求,故代码里有加入延迟处理。接口

#ifndef __DS18B20_H__
#define __DS18B20_H__
#include <reg52.h>

sbit wire = P2^2;//GPIO P2.2
extern unsigned char ROM[8];

//bit DS18B20_RST(void);		//一、复位初始化DS18B20,若是返回0则初始化失败
//void write_1_byte_DS18B20(unsigned char);	//二、向DS18B20写1字节
//unsigned char read_1_byte_DS18B20(void);	//三、读DS18B20 1字节  以前的读取多移动了一位,哎 sb了

void view_DS18B20(void);//四、读取DS18B20 ROM编码 //0x33表示读取64位ROM编码0x55表示匹配ROM对应的器件0xf0表示搜索ROM
void acc_DS18B20(char TH, char TL, unsigned char z);//五、配置一个器件的TH高温报警温度和TL低温报警温度和温度精度z

void convert_DS18B20(unsigned char); //六、转换温度,x为选择使用的精度9位 10位 11位 12位,默认12位
void copy_acc_EEPROM_DS18B20(void); //七、拷贝配置好的寄存器的值到EEPROM里
void recall_EEPROM_DS18B20(void);//八、召回EEPROM里的3个字节数据到寄存器对应里面(高温、低温、精度)

bit wire_status_DS18B20(void); //九、读取DS18B20反馈状态 1bit 这个好像没什么用处
float read_temp_DS18B20(unsigned char);//十、读取DS18B20的温度,输入选择的精度9位 10位 11位 12位 9 10 11 12,默认12位


#endif
#include "delay.h"
#include <intrins.h>
#include "led.h"
#include "ds18b20.h"
//与DS18B20通信传输数据的时候均是先传送低位最后传送高位
unsigned char ROM[8];

//一、复位初始化DS18B20
bit DS18B20_RST(void)
{
	wire = 0;
	delay_us(75);	//拉低480us复位DS18B20
	wire = 1;		//释放数据线
	delay_us(8);	//延迟60us开始判断是否有应答信号
	if(wire)		//没有应答的话
	{
		delay_us(26);//延迟180us二次判断DS18B20回复存在信号,即应答ACK信号
		if (wire)//尚未应答的话
		{
			return 0;//当函数返回0表示DS18B20初始化失败
		}
		else//有应答信号了
		{
			delay_us(26);//延迟180us判断是否器件释放总线
			if (wire)//释放总线的话
			{
				delay_us(26);//再次延长180us
				return 1;//当函数返回1表示DS18B20初始化成功
			}
			else
			{
				return 0;//当函数返回0表示DS18B20初始化失败
			}
		}
	}
	else//有应答信号了
	{
		delay_us(38);//延长240us
		if (wire == 1)//若是器件释放总线的话
		{
			delay_us(38);//再次延长240us
			return 1;//当函数返回1表示DS18B20初始化成功
		}
		else
		{
			return 0;//当函数返回0表示DS18B20初始化失败
		}
	}
}   

//二、向DS18B20写1字节
void write_1_byte_DS18B20(unsigned char x)
{
	unsigned char i=0;
	for (i;i < 8;i++)
	{
		wire = 0;
		_nop_();	//延迟大于1us
		wire = x & 0x01;
		delay_us(8);//延迟60us让DS18B20好采样
		wire = 1;//释放总线
		x = x >> 1;
	}
}

//三、读DS18B20 1字节。。。。马来币以前dat返回数据没有取反,总线没有释放就直接读取数据了
unsigned char read_1_byte_DS18B20(void)
{
	unsigned char i;
	unsigned char dat=0;
	for ( i=0 ; i  < 8; i ++)
	{
		dat = dat >> 1;//放在for循环后面有问题,会向右多移动一位,怪不得以前的数据读取出来有问题
		wire = 0;
		_nop_();
		wire = 1;//释放总线,等待DS18B20发送数据到总线上
		_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();//延迟个6us时间在采集数据

		if(wire)//这个if里面的数不建议写成if(wire);推荐写成if(wire==1);
		{
			dat += 0x80;
		}
		wire = 1;//释放总线
		delay_us(8);//延迟60us	
	}
	return dat;
}

//四、读取DS18B20 ROM编码  ,须要读取DS18B20 ROM编码
void view_DS18B20(void)	//0x33表示读取64位ROM编码0x55表示匹配ROM对应的器件0xf0表示搜索ROM
{
	unsigned char i;
	DS18B20_RST();
	write_1_byte_DS18B20(0x33);
	for (i = 0; i < 8; i++)
	{
		ROM[i] = read_1_byte_DS18B20();
	}
}

//五、配置一个器件的TH高温报警温度和TL低温报警温度和温度精度z
void acc_DS18B20(char TH,char TL,unsigned char z)
{
	unsigned char i;//用来存储精度对应的指令
	switch (z)
	{
	case  9:i = 0x1f;break;
	case 10:i = 0x3f;break;
	case 11:i = 0x5f;break;
	case 12:i = 0x7f;break;
	default:i = 0x7f;//默认12位精度
		break;
	}
	DS18B20_RST();//复位初始化成功
	write_1_byte_DS18B20(0xcc);	//跳过64位ROM码检测
	write_1_byte_DS18B20(0x4e);//配置寄存器指令。马来币这个语句忘记写了 不写那么配置数据坑定写不进去啊
	write_1_byte_DS18B20(TH);	//配置高温报警温度 最高位为1则表示负温度,为0则表示正温度,±1℃
	write_1_byte_DS18B20(TL);	//配置低温报警温度
	write_1_byte_DS18B20(i);	//i=0001 1111 0x1f 9位精度,转换时间93.75ms
								//i=0011 1111 0x3f 10位精度,转换时间187.5ms
								//i=0101 1111 0x5f 11位精度,转换时间375ms
								//i=0111 1111 0x7f 12位精度,转换时间750ms
}

//六、转换温度,x为选择使用的精度9位 10位 11位 12位,默认12位
void convert_DS18B20(unsigned char x)
{
	DS18B20_RST();	//初始化函数
	write_1_byte_DS18B20(0xcc);	//跳过64位ROM码检测
	write_1_byte_DS18B20(0x44);	//温度转换指令-功能命令
					//x=0001 1111 0x1f 9位精度,转换时间93.75ms
					//x=0011 1111 0x3f 10位精度,转换时间187.5ms
					//x=0101 1111 0x5f 11位精度,转换时间375ms
					//x=0111 1111 0x7f 12位精度,转换时间750ms
	switch (x)
	{
		case 9:	delay_ms(95);	break;
		case 10:delay_ms(190);	break;
		case 11:delay_ms(380);	break;
		case 12:delay_ms(750);	break;
		default:delay_ms(900);	break;//默认按照12位精度转换时间
	}
}

//七、拷贝配置好的寄存器的值到EEPROM里
void copy_acc_EEPROM_DS18B20(void)
{
	DS18B20_RST();//初始化函数
	write_1_byte_DS18B20(0xcc);	//跳过64位ROM码检测
	write_1_byte_DS18B20(0x48);//将配置好的寄存器的值拷贝到EEPROM里
}

//八、召回EEPROM里的3个字节数据到寄存器对应里面(高温、低温、精度)
void recall_EEPROM_DS18B20(void) //召回EEPROM里的3个字节数据到寄存器对应里面(高温、低温、精度)
{	
	DS18B20_RST();	//初始化DS18B20函数
	write_1_byte_DS18B20(0xcc);	//跳过64位ROM码检测
	write_1_byte_DS18B20(0xb8);	//操做指令将EEPROM里的数据拷贝到寄存器里
}

//九、读取DS18B20反馈状态 1bit   这个好像没什么用处
bit wire_status_DS18B20(void)
{
	if(!wire)
	{
		delay_ms(1000);//延长1s时间
		if (!wire)
		{
			return 1;//转换时长太长了,转换失败
		}
		else
		{
			LED_shan_suo(2);//led灯闪烁2次
			return 0;//转换完成
		}
	}
	LED_shan_suo(2);//led灯闪烁2次
	return 0;//转换完成
}

//十、读取DS18B20的温度,输入选择的精度9位 10位 11位 12位 9 10 11 12,默认12位
float read_temp_DS18B20(unsigned char x)
{
	bit a;//临时变量负责判断温度是正数仍是负数,正数为0,负数为1
	unsigned char TL = 0;
	unsigned int TH = 0;
	float result;
	DS18B20_RST();//复位器件
	write_1_byte_DS18B20(0xcc);//跳过ROM检测指令
	write_1_byte_DS18B20(0xbe);//读取暂存寄存器使用的指令
	TL = read_1_byte_DS18B20();//将读取的低温8位存起来
	TH = read_1_byte_DS18B20();//将读取的高温8位存起来
	DS18B20_RST();//强制复位,后面的数据不在读取了
	//开始使用算法计算温度
	if (TH < 8)
	{
		a = 0;//为正数
	}
	else
	{
		a = 1;//为负数
	}
	TH <<= 8;
	TH += TL;//TH = TH | TL;
	if (a)//判断TH是否是负温度
	{
		TH = ~TH + 1;//先转换为正数,主要是要处理数据
	}
	switch (x)
	{
		case	9:	TH>>=3;result = TH * 0.5;			break;//右移表示精度不须要过高须要匹配9位精度
		case	10:	TH>>=2;result = TH * 0.25;		break;//右移表示精度不须要过高须要匹配10位精度
		case	11:	TH>>=1;result = TH * 0.125;		break;//右移表示精度不须要过高须要匹配11位精度
		case	12:	TH>>=0;result = TH * 0.0625;	break;
		default:result = TH * 0.0625;					break;
	}
	if (!a)
	{
		return result;//返回正小数
	}
	else
	{
		return -result;//返回负小数
	}
}
//十一、搜索是否温度有报警0xec指令 只有温度超过设定值后才会响应