/*-------------------------------------------------------------------                                                            
程序名称:   在1602液晶上显示出DS18B20的温度值                                                                       
-------------------------------------------------------------------*/

#include <reg52.h>      
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit ds=P2^2;  //定义DS18B20通信端口
sbit lcd_rs = P3^5;  //定义LCD控制端口
sbit lcd_rw = P3^6;
sbit lcd_en = P3^4;
#define P0 P0
sbit dula=P2^6; //数码管段选
sbit wela=P2^7; //数码管位选
uchar code mun_to_char[] = {"0123456789ABCDEF"}; //定义数字跟ASCII码的关系
uchar data lcd1602_line1[]={"YL-51MCU DS18B20"}; //LCD1602液晶第一行
uchar data lcd1602_line2[]={"TEMP:00.0       "}; //LCD1602液晶第二行。注意：用7个空格补够16个字符位
bit flag;
uint temp;

void delayus(uint t)   //微秒级的延时函数
{
	while(t--);
}

void ds_reset()    //单总线初始化函数
{
	ds=1;           
	delayus(5);     
	ds=0;          
	delayus(80);    
	ds=1;          
	delayus(14);    
	if(ds==0)      
		flag=1;    
	else
		flag=0;    
	delayus(20);
}

bit ds_read_bit()    //读时隙（即位读取）函数
{
	bit dat;        
	ds=0;        
	_nop_();       
	_nop_();       
	ds=1;        
	_nop_();     
	dat=ds;       
	delayus(10);  
	return dat;    
}

uchar ds_read_byte()   //读一个字节函数
{
	uchar i,j,k;
	for(i=0;i<8;i++)   
	{
		j=ds_read_bit();   
		    k=(j<<7)|(k>>1);  
	}
	return k;  
}

void ds_write_byte(uchar dat)   //写一个字节函数
{
	uchar i;
	for(i=0;i<8;i++)      
	{
		ds=0;          
		_nop_();        
		ds=dat&0x01;    
		delayus(6);     
		ds=1;         
		dat=dat>>1;     
	}
		delayus(6);    
}

uint read_temperature()   //读取温度函数
{
	uchar a,b;
	ds_reset();            
	ds_write_byte(0xcc);   
	ds_write_byte(0xbe);   
	a=ds_read_byte();    
	b=ds_read_byte();   
	temp=b;
	temp=temp<<8;
	temp=temp|a;      
	    temp=temp*0.0625*10+0.5;  
	return temp;  
}


//------------------1602液晶---------------------------

void lcd_delay(uchar x) //LCD1602 延时
{
	uint i,j;
    for(i=x;i>0;i--)
	{
		for(j=120;j>0;j--);
	}
}

void write_com(uchar com) //LCD1602 命令字写入
{

    lcd_rs = 0;
    lcd_rw = 0;
    lcd_en = 0;
    P0 = com;
    lcd_en = 1;
	lcd_delay(5);
    lcd_en = 0;     
}

void lcd_init() //LCD1602 初始化
{
    write_com(0x38);
    write_com(0x08);
    write_com(0x01);
    write_com(0x06);
    write_com(0x0c); //开显示,不显示光标
}

void lcd_char_write(uchar x_pos,y_pos,lcd_dat) //LCD1602 字符写入
{
    x_pos &= 0x0f; // X位置范围 0~15
    y_pos &= 0x01; // Y位置范围 0~ 1
    if(y_pos==1) x_pos += 0x40;
    x_pos += 0x80;
    write_com(x_pos);
	lcd_delay(5);
    lcd_rs = 1;
    lcd_rw = 0;
    lcd_en = 0;
    P0 = lcd_dat;
    lcd_en = 1;
    lcd_en = 0; 
	P0 = 0xff; //释放数据端口
}

void main()
{
	uchar i;
	uint temp1; 
	lcd_en=0;  //关闭1602液晶使能，防止1602数据端影响单片机P0口输出
	wela=1;
	P0=0xff;
	wela=0;   //关闭数码管位选
	lcd_init(); //LCD1602 初始化
	while(1)
		{
			ds_reset();       //单总线初始化
			ds_write_byte(0xcc);   //跳线ROM
			ds_write_byte(0x44);   //启动温度传换
			temp1=read_temperature(); //读取当前温度值
			lcd1602_line2[5] = mun_to_char[temp1/100];   //把当前温度分解送到1602显示
			lcd1602_line2[6] = mun_to_char[temp1%100/10];
			lcd1602_line2[8] = mun_to_char[temp1%10]; 
			for(i=0;i<16;i++) lcd_char_write(i,0,lcd1602_line1[i]);
	  		for(i=0;i<16;i++) lcd_char_write(i,1,lcd1602_line2[i]);
		}

}



