使用51单片机和DS18B20传感器实现温度测量并在LCD1602上显示

文章目录

  • 介绍
  • Proteus运行仿真图
  • 源程序
  • 主函数
  • 自定义头文件
  • LCD1602函数
  • DS18B20
  • 共用函数
  • 介绍

    通过DS18B20采集温度在LCD1602上显示
    第一行显示温度第二行显示精度
    

    Proteus运行仿真图

    源程序

    主函数

    #include<reg51.h>
    #include "mine.h"
    uchar code WenDu[]={"Tempture:"};
    uchar code JingDu[]={"Accuracy:0.0625"};
    uchar code Sz[]={"0123456789"};
    int Tempture; 
    void main()
    { LCD_Init();
    	ds18b20Init();
    	ds18b20Start();
    	delayxms(1000);
    	while(1)
    	{
    	TemptureDisplay();
    	}
    }
    void TemptureDisplay()
    {
    	uint i,Bai,Ge,Shi;
    	Tempture=ds18b20ReadTemperture()*10;
    	/*温度是正还是负*/
    	if(Tempture<0)
    	 {
    	   Tempture=-Tempture;
    		 DisplayChar(1,9,'-');
    	 }
    	 else DisplayChar(1,9,'+');
    	 /*取出温度每一位*/
    	 Bai=Tempture/100;
    	 Ge=Tempture%10;
    	 Shi=(Tempture%100)/10;
    	 /*显示Tempture:*/
    	 for(i=0;i<9;i++)
    	 DisplayChar(1,i,WenDu[i]);
    	 /*显示Accuracy:*/
    	 for(i=0;i<15;i++)
    	 DisplayChar(2,i,JingDu[i]);
    	 /*显示.°C*/
    	 DisplayChar(1,12,'.');
    	 DisplayChar(1,14,0xdf);
    	 DisplayChar(1,15,'C');
    	 /*显示温度整数部分*/
    	 DisplayChar(1,10,Sz[Bai]);
    	 DisplayChar(1,11,Sz[Shi]);
    	 /*显示小数部分*/
    	 DisplayChar(1,13,Sz[Ge]);
    }
    

    自定义头文件

    #ifndef _MINE_H          
    #define _MINE_H
    #include<reg51.h>
    #define uint unsigned int
    #define uchar unsigned char
    /**************************************ds18b20模块声明*******************************
    复位*检查是否存在*读一位*读一个字节*写一个字节*开始读温度*初始*读温度并转换*显示温度*
    ************************************************************************************/
    void ds18b20Rest();
    uchar ds18b20Check();
    uchar ds18b20ReadBit();
    uchar ds18b20ReadByte();
    void ds18b20WriteByte(uchar dat);
    void ds18b20Start();
    uchar ds18b20Init();
    float ds18b20ReadTemperture();
    void TemptureDisplay();
    sbit DQ=P3^3;
    /*************************LCD1602模块声明**************************
    ****************查忙*写数据*写命令*初始化*显示一个字符*************
    *******************************************************************/
    void Busy();
    void W_Data(uchar dat);
    void W_Cmd(uchar cmd);
    void LCD_Init();
    void DisplayChar(uchar y , uchar  x , uchar dat );
    sbit rs=P2^0;          
    sbit rw=P2^1;  
    sbit e=P2^2;
    /***********共用模块声明*********
    定时器T0初始化*延时10us*延时xms*/
    void delay10us(uint us);
    void delayxms(uint x);
    #endif
    

    LCD1602函数

    #include<reg51.h>
    #include "mine.h"
    /*检查是否忙*/
    void Busy()		
    {do
      {
    		e=0;
    		rs=0;
    		rw=1;
    		P0=0Xff;
    		e=1;
      } while (P0^7==1); 
    }
    /*lcd1602写指令函数*/
    void W_Cmd(uchar cmd)
    	{
        
        P0=cmd;//要写入的命令
        rs=0; //低电平写指令         
        rw=0; //选择写
    		e=0;
    	  delayxms(2);
        e=1; 
        delayxms(2);	
        e=0;
    }
    /*lcd1602写数据函数*/
    void W_Data(uchar dat )
    { 
        P0=dat;//要写入的数据
        rs=1;  //高电平写数据         
        rw=0;  //选择写 
        e=0;	
        delayxms(2);  
    	  e=1;                
        delayxms(2);  
    	  e=0;
    }
    
    /*初始化*/
    void LCD_Init()
    {
      W_Cmd(0x38);//16列两行,8位数据口(指令6)
    	W_Cmd(0x0c);//开显示 关光标 不闪烁(指令4)
    	W_Cmd(0x06);//写一个数据后,显示位置右移一位(指令3)
    	W_Cmd(0x01);//清屏(指令1)
    }
    /*在指定的位置显示一个字符*/
    void DisplayChar(uchar y , uchar  x , uchar dat )
    {    
       uchar address;
        if (y==1)                  //等于1使用第一行显示
             address=0x80+x;       //第一行起始地址80H,加x为最终显示字符地址
        else
       address=0xc0+x;             //第二行起始地址c0H,加x为最终显示字符地址
       W_Cmd(address);  //写入地址 
       W_Data(dat);         //写入数据
    }
    
    

    DS18B20

    #include<intrins.h>
    #include "mine.h"
    /***************复位**********/
    void ds18b20Reset()
    {
     DQ=0;
     delay10us(75);//拉低DQ,750us(480~960)
     DQ=1;
     delay10us(2);//DQ=1,20US(15~60)
    }
    /*******检测18b20是否存在**********/
    uchar ds18b20Check()
    {
    	uchar time_temp=0;
    	while(DQ&&time_temp<20)	//等待DQ为低电平,如果一直高电平且超过200us退出,
    	{
    		time_temp++;
    		delay10us(1);	
    	}
    	if(time_temp>=20)return 1;//ds18b20没有响应
    	else time_temp=0;//检测到ds18b20
    	while((!DQ)&&time_temp<20)
    	{
    	time_temp++;
    	delay10us(1);
    	}
    	if(time_temp>=20)return 1;	//如果超时则强制返回1
    	return 0;//检测到响应
    }
    /*********温度读取(一位)**********/
    uchar ds18b20ReadBit()
    {
    	uchar dat=0;
    	DQ=0;
    	_nop_();_nop_();
    	DQ=1;	
    	_nop_();_nop_(); //该段时间不能过长,必须在15us内读取数据
    	if(DQ)dat=1;	//读1
    	else dat=0;//读0
    	delay10us(6);
    	return dat;
    } 
    /*******温度读取(一个字节)**********/
    uchar ds18b20ReadByte()
    {
    	uchar i=0;
    	uchar dat=0;
    	uchar temp=0;
    	for(i=0;i<8;i++)//循环8次,每次读取一位,且先读低位再读高位
    	{
    		temp=ds18b20ReadBit();
    		dat=(temp<<7)|(dat>>1);//temp左移7位或上dat右移1位
    	}
    	return dat;	
    }
    /*******温度写入(一个字节)**********/
    void ds18b20WriteByte(uchar dat)
    {
    	uchar i=0;
    	uchar temp=0;
    	for(i=0;i<8;i++)//循环8次,每次写一位,且先写低位再写高位
    	{
    		temp=dat&0x01;//取出低位,选择低位准备写入
    		dat>>=1;//将次高位移到低位右移
    		if(temp)
    		{
    			DQ=0;
    			_nop_();_nop_();//延时2us(>1us)
    			DQ=1;//释放总线
    			delay10us(6);//至少60us
    		}
    		else
    		{
    		DQ=0;//写0与写1延时相反
    		delay10us(6);
    		DQ=1;
    		_nop_();_nop_();	
    		}	
    	}	
    }
    void ds18b20Start()
    {
      ds18b20Reset();//复位
    	ds18b20Check();//检查DS18B20
    	ds18b20WriteByte(0xcc);//SKIP ROM
      ds18b20WriteByte(0x44);//转换命令	
    }
    uchar ds18b20Init()
    {
    	ds18b20Reset();
    	return ds18b20Check();	
    }
    /***********温度读取*********/
    float ds18b20ReadTemperture()
    {
    	float temp;
    	uchar datH=0;
    	uchar datL=0;
    	uint value=0;
    	ds18b20Start();//开始转换
    	ds18b20Reset();//复位
    	ds18b20Check();
    	ds18b20WriteByte(0xcc);//SKIP ROM
      ds18b20WriteByte(0xbe);//读存储器
    	datL=ds18b20ReadByte();//低字节
    	datH=ds18b20ReadByte();//高字节
    	value=(datH<<8)+datL;//合并为16位数据
    	if((value&0xf800)==0xf800)//0xf800(1111 1000 0000 0000)判断符号位,负温度(前五位正负后五位温度)
    	{
    	value=(~value)+1; //数据取反再加1
    	temp=value*(-0.0625);//乘以精度	
    	}
    	else //正温度
    	{
    	temp=value*0.0625;	
    	}
    	return temp;
    }
    

    共用函数

    #include<reg51.h>
    #include "mine.h"
    void T0_init()
    {
    	TMOD=0x01;//设置定时器0
    	TH0=0x3c;//装初值
    	TL0=0xb0;
    	EA=1;//开总中断
    	ET0=1;//开定时器0中断
    	TR0=1;//启动定时器0
    }
    void delay10us(uint us)
    {
    	while(us--);	
    }
    void delayxms(uint x)
    {
    	uint i,j;
    	for(i=0;i<x;i++)
    	for(j=0;j<110;j++);
    }
    
    显示负数的时候小数位会有偏差但不知道原因
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用51单片机和DS18B20传感器实现温度测量并在LCD1602上显示

    发表评论