//------------------------------------------------------------------//DS18B20温度传感器输出显示,运行本例时,外界温度将显示在1602LCD上//------------------------------------------------------------------#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define delayNOP() {_nop_();_nop_();_nop_();_nop_();}sbit DQ=P2^2;sbit dula=P2^6; //定义锁存器锁存端sbit wela=P2^7;sbit rs=P3^5; //定义1602液晶RS端sbit lcden=P3^4;//定义1602液晶LCDEN端sbit s1=P3^0; //定义按键--功能键sbit s2=P3^1; //定义按键--增加键sbit s3=P3^2; //定义按键--减小键sbit s4=P3^6;//闹钟查看键sbit rd=P3^7;sbit beep=P2^3; //定义蜂鸣器端uchar code Temp_Disp_Title[]={" Current Temp : "};uchar Current_Temp_Display_Buffer[]={" TEMP: "};uchar code Alarm_Temp[]={"ALARM TEMP Hi Lo"};uchar Alarm_HI_LO_STR[]={"Hi: Lo: "};uchar temp_data[2]={0x00,0x00};uchar temp_alarm[2]={0x00,0x00};uchar display[5]={0x00,0x00,0x00,0x00,0x00};uchar display1[3]={0x00,0x00,0x00};uchar code df_Table[]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};uchar CurrentT=0; //当前读取的温度整数部分uchar Temp_Value[]={0x00,0x00}; //从DS18B20读取的温度值uchar Display_Digit[]={0,0,0,0}; //待显示的各温度数位bit DS18B20_IS_OK=1;//传感器正常标志//-------------------------------------//延时1//-------------------------------------void delay1(uint x){ uchar i; while(x--) for(i=0;i<200;i++);}//-------------------------------------//延时2//-------------------------------------void Delay(uint x){ while(x--);}//------------------------------------//忙检查//------------------------------------void write_com(uchar com)//液晶写命令函数{ rs=0; lcden=0; P0=com; delay1(5); lcden=1; delay1(5); lcden=0; }void Write_LCD_Data(uchar date)//液晶写数据函数{ rs=1; lcden=0; P0=date; delay1(5); lcden=1; delay1(5); lcden=0; }//-----------------------------//设置LCD显示位置//---------------------------------void Set_Disp_Pos(uchar Pos){ write_com(Pos|0x80);}//-----------------------------//LCD初始化//---------------------------------void Initialize_LCD(){ uchar num; rd=0; //软件将矩阵按键第4列一端置低用以分解出独立按键 dula=0;//关闭两锁存器锁存端,防止操作液晶时数码管会出乱码 wela=0; lcden=0; write_com(0x38);//初始化1602液晶 write_com(0x0c); write_com(0x06); write_com(0x01); write_com(0x80);//设置显示初始坐标 for(num=0;num<14;num++)//显示年月日星期 { Write_LCD_Data(Temp_Disp_Title[num]); delay1(5); }}//-------------------------------------//函数功能:初始化DS18B20//出口参数:status---DS18B20是否复位成功的标志//-------------------------------------uchar Init_DS18B20(){ uchar status; //储存DS18B20是否存在的标志,status=0,表示存在;status=1,表示不存在 DQ=1;Delay(8); //先将数据线拉高 //略微延时约6微秒 DQ=0;Delay(90); //再将数据线从高拉低,要求保持480~960us //略微延时约600微秒 以向DS18B20发出一持续480~960us的低电平复位脉冲 DQ=1;Delay(8); //释放数据线(将数据线拉高) //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲) status=DQ;Delay(100); //让单片机检测是否输出了存在脉冲(DQ=0表示存在) //延时足够长时间,等待存在脉冲输出完毕 DQ=1; // 将数据线拉高 return status; //返回检测成功标志}//-------------------------------------//函数功能:读一字节//出口参数:dat---读出的数据//-------------------------------------uchar ReadOneByte(){ uchar i,dat=0; DQ=1;_nop_(); // 先将数据线拉高 //等待一个机器周期 for (i=0;i<8;i++) { DQ=0; //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序 dat>>=1; _nop_(); //等待一个机器周期 DQ=1; //将数据线"人为"拉高,为单片机检测DS18B20的输出电平作准备 _nop_();_nop_(); //延时约6us,使主机在15us内采样 if (DQ) dat|=0x80; //如果读到的数据是1,则将1存入dat,如果是0则保持原值不变 Delay(30); //延时3us,两个读时序之间必须有大于1us的恢复期 DQ=1; // 将数据线拉高,为读下一位数据做准备 } return dat; }//-------------------------------------//函数功能:写一字节//入口参数:dat---待写入的数据//-------------------------------------void WriteOneByte(uchar dat){ uchar i; for (i=0;i<8;i++) { DQ=0; //将数据线从高拉低时即启动写时序 DQ=dat & 0x01; //利用与运算取出要写的某位二进制数据, //并将其送到数据线上等待DS18B20采样 Delay(5); //延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样 DQ=1; //释放数据线 dat>>=1; //将dat中的各二进制位数据右移1位 }}//-------------------------------------//函数功能:读取温度值//出入口参数:无//-------------------------------------void Read_Temperature(){ if(Init_DS18B20() == 1) //DS18B20故障 DS18B20_IS_OK=0; else { WriteOneByte(0xCC); // 跳过读序号列号的操作 WriteOneByte(0x44); // 启动温度转换 Init_DS18B20(); //将DS18B20初始化 WriteOneByte(0xCC); //跳过读序号列号的操作 WriteOneByte(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位 Temp_Value[0]=ReadOneByte(); //温度低8位 Temp_Value[1]=ReadOneByte(); //温度高8位 DS18B20_IS_OK=1; }}//-------------------------------------//函数功能:在LCD上显示当前温度//入口参数://-------------------------------------void Display_Temperature(){ uchar i; //延时值与负数标识 uchar t=150,ng=0; //高5位全为1(0xF8)则为负数,为负数时取反加1,并设置负数标示 if ((Temp_Value[1] & 0xF8)==0xF8) { Temp_Value[1]=~Temp_Value[1]; Temp_Value[0]=~Temp_Value[0]+1; if(Temp_Value[0]==0x00) Temp_Value[1]++; //加1后如果低字节为00表示有进位,进位位再加到高字节上 ng=1; //负数标示置1 } Display_Digit[0]=df_Table[Temp_Value[0] & 0x0F]; //查表得到温度小数部分 //获取温度整数部分(高字节的低3位与低字节中的高4位,无符号) CurrentT=((Temp_Value[0] & 0xF0)>>4)|((Temp_Value[1] & 0x07)<<4); //将整数部分分解为3位待显示数字 Display_Digit[3]=CurrentT/100; //百位 digit[CurrentT/100]; Display_Digit[2]=CurrentT%100/10; //十位 Display_Digit[1]=CurrentT%10; //个位 //刷新LCD显示缓冲 Current_Temp_Display_Buffer[11]=Display_Digit[0]+'0';//先将'0'转换成整数48,然后与前面数字相加,得到相应数字的ASCII字符 Current_Temp_Display_Buffer[10]='.'; Current_Temp_Display_Buffer[9]=Display_Digit[1]+'0'; //个位 Current_Temp_Display_Buffer[8]=Display_Digit[2]+'0'; //十位 Current_Temp_Display_Buffer[7]=Display_Digit[3]+'0'; //百位 //高位为0时不显示 if(Display_Digit[3]==0) Current_Temp_Display_Buffer[7]=' '; //高位为0且次高位为0时,次高位不显示 if(Display_Digit[2]==0 && Display_Digit[3]==0) Current_Temp_Display_Buffer[8]=' '; //负数符号显示在恰当位置 if(ng) { if (Current_Temp_Display_Buffer[8]==' ') Current_Temp_Display_Buffer[8]='-'; else if(Current_Temp_Display_Buffer[7]==' ') Current_Temp_Display_Buffer[7]='-'; else Current_Temp_Display_Buffer[6]='-'; } //在第一行显示标题 Set_Disp_Pos(0x00); for(i=0;i<16;i++) { Write_LCD_Data(Temp_Disp_Title[i]); } Set_Disp_Pos(0x40); //在第二行显示当前温度 for(i=0;i<16;i++) { Write_LCD_Data(Current_Temp_Display_Buffer[i]); } //显示温度符号// Set_Disp_Pos(0x4D);Write_LCD_Data(0x00); Set_Disp_Pos(0x4D);Write_LCD_Data(0xdf); Set_Disp_Pos(0x4E); Write_LCD_Data('C');}//-------------------------------------//函数功能:主函数//入口参数://------------------------------------- void main(){ Initialize_LCD(); Read_Temperature(); Delay(50000); Delay(50000); while (1) { Read_Temperature(); if (DS18B20_IS_OK) Display_Temperature(); delay1(100); }}