51单片机DS18B20温度传感器使用及数码管温度计、LCD1602温度显示代码详解

温馨提示:读者若要彻底理解并会灵活使用DS18B20温度传感器,请详细阅读中文手册,并且对照代码注释充分分析代码。请不要觉得中文手册内容繁多!如能静心分析,定能深有体会,获益匪浅!

一、DS18B20中文手册(节选)

主函数操作顺序(执行序列)

功能指令

数码管温度计详解代码如下:


#include <reg52.h>
#include <intrins.h>
#define MAIN_Fosc     11059200UL    //宏定义主时钟HZ
/*====================================
 自定义类型名
====================================*/
typedef unsigned char INT8U;
typedef unsigned char uchar;

typedef unsigned int INT16U;
typedef unsigned int uint;

/*====================================
 硬件接口位声明
====================================*/
sbit DS  = P2^2;   //DS18B20单总线
sbit DU  = P2^6;   //数码管段选
sbit WE  = P2^7;   //数码管位选
/*====================================
共阴极数码管段选码
====================================*/
uchar code table[]={ 
//0        1     2     3     4     5     6     7     8
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,
//9     A     B       C     D       E     F        -     .      关显示
0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x40, 0x80, 0x00
                   };

/*====================================
数码管位选码
====================================*/
                  //第1位    2位      3位     4位   5位    6位      7位    8位
uchar code T_COM[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};//数码管位码

/*====================================
函数:void Delay_Ms(INT16U ms)
参数:ms,毫秒延时形参
描述:12T 51单片机自适应主时钟毫秒级延时函数
====================================*/
void Delay_Ms(INT16U ms)
{
     INT16U i;
     do{
          i = MAIN_Fosc / 96000; 
          while(--i);   //96T per loop
     }while(--ms);
}
/*us延时函数,执行一次US--所需6.5us进入一次函数需要11.95us*/
void Delay_us(uchar us)
{
    while(us--);    
}
/*====================================
函数:void Display(INT16U Value)
参数:Value,显示值 取值0-65535
描述:共阴极数码管显示函数可显示一个字节的数
====================================*/
void Display(INT16U Value)            //注意由于需要显示的数大于一个字节所有形参需为int型
{    
//------------------------------
    DU = 0;                            //关闭段选
    P0 = table[Value/100];        //数码管显示百位
    DU = 1;                            //打开段选
    DU = 0;                            //关闭段选

    WE = 0;                        //关闭位选
    P0 = T_COM[0];                //第一位数码管
    WE = 1;                        //打开位选
    WE = 0;                        //关闭位选
    Delay_Ms(3);
//-------------------------------
    DU = 0;
    P0 = table[Value%100/10]|0x80; //显示十位
    DU = 1;
    DU = 0;

    WE = 0;
    P0 = T_COM[1];              //第二位数码管
    WE = 1;
    WE = 0;
    Delay_Ms(3);
//-------------------------------
    DU = 0;
    P0 = table[Value%10];        //显示个位
    DU = 1;
    DU = 0;

    WE = 0;
    P0 = T_COM[2];                //第三位数码管
    WE = 1;
    WE = 0;
    Delay_Ms(3);
}
/*单总线初始化时序*/
/*出始化时序里包含了复位DS18B20和接收DS18B20返回的存在信号*/
bit ds_init() 
{
    bit i;
    DS = 1;
    _nop_();
    DS = 0;
    Delay_us(75); //拉低总线499.45us 挂接在总线上的18B20将会全部被复位
    DS = 1; //释放总线(检测到上升沿)
    Delay_us(4); //延时37.95us 等待18B20发回存在信号(存在脉冲)
    i = DS;
    Delay_us(20); //141.95us
    DS = 1;
    _nop_();
    return (i);    //返回一个存在信号
}
/*写一个字节*/
void write_byte(uchar dat)
{
    uchar i;
    for(i=0;i<8;i++)
    {
        DS = 0;
        _nop_();//产生些时序
        DS = dat & 0x01; //0000 0001
        Delay_us(10);//76.95us
        DS = 1; //释放总线准备下一次数据写入
        _nop_();
        dat >>= 1;
    }
}

uchar read_byte()
{
    uchar i, j, dat;
    for(i=0;i<8;i++)
    {
        DS = 0;
        _nop_();//产生读时序 1us,延时一个指令周期,空指令
        DS = 1;    //释放总线
        _nop_(); //延时时间可以通过单步调试来计算
        j = DS;
        Delay_us(10);//76.95us
        DS = 1;
        _nop_();
        dat = (j<<7)|(dat>>1);    
    }
    return (dat);
}
void main()
{
    uint i;
    uchar L, M;
    while(1)
    {
        ds_init();//初始化DS18B20
        write_byte(0xcc);//发送跳跃ROM指令
        write_byte(0x44);//发送温度转换指令
        ds_init();//初始化DS18B20
        write_byte(0xcc);//发送跳跃ROM指令(注意:当只有一只从机在总线上时,无论如何,
        //忽略ROM指令之后只能跟着发出一条暂存器指令【BEh】)
        write_byte(0xbe);//读取DS18B20暂存器值,读取将从字节0开始,一直进行下去,直到第9字节(字节8,CRC)读完
        L = read_byte();//总线控制器在发出温度转换指令之后进行读时序
        M = read_byte();//总线控制器在发出温度转换指令之后进行读时序
        i = M; //高速暂存器(共8位),详见中文手册
        i <<= 8; //将最低位移至高位
        i |= L;                        
        i = i * 0.0625 * 10 + 0.5;
        Display(i);
    }
}

LCD1602温度显示


#include <reg52.H>
#include <intrins.H>
#include <math.H>

#define uchar unsigned char
  #define uint unsigned int
 sbit dula = P2^6;//数码管段选
 sbit wela = P2^7;//数码管位选
 sbit rw = P3^6; //LCD1602读/写选择端
 sbit RS = P3^5;//LCD1602数据/命令选择端  
  
 sbit LCDEN = P3^4; //LCD1602使能端

void delayUs()
{
    _nop_();  //空指令,延时一个指令周期
}

 void delayMs(uint a)
{
    uint i, j;
    for(i = a; i > 0; i--)
        for(j = 100; j > 0; j--);
 }


void writeComm(uchar comm) //写指令
{
    RS = 0;    
    P0 = comm;
    LCDEN = 1;
    delayUs();
    LCDEN = 0;
    delayMs(1);
}

//写数据:RS=1, RW=0;
void writeData(uchar dat)
{
    RS = 1;
    P0 = dat;
    LCDEN = 1;
    delayUs();
    LCDEN = 0;
    delayMs(1);
 }


 void init() //LCD1602初始化函数
 {
    rw = 0; //LCD1602读/写选择端
    dula = wela = 0;
    writeComm(0x38);//LCD1602显示设置
    writeComm(0x0c);//开显示 
    writeComm(0x06);//当读或写一个字符后地址指针加一,且光标加一
    writeComm(0x01);//清屏指令 
}

void writeString(uchar * str, uchar length)//LCD1602写字符串
{
     uchar i;
    for(i = 0; i < length; i++)
    {
         writeData(str[i]);
     }
 }
 
/**//*****************************DS18B20*******************************/

/*温馨提示:读者若要彻底理解并会灵活使用DS18B20温度传感器,请详细阅读
中文手册,并且对照代码注释充分分析代码。如能静心分析,定能深有体会,获
益匪浅!*/
sbit ds = P2^2;
void dsInit()//初始化,详见中文手册
 {
    
    unsigned int i;  
    ds = 0;
    i = 100;  
    while(i>0) i--;    //用于延时(严格按照时序来写)
    ds = 1;   
    i = 4;
    while(i>0) i--;
 }
 
void dsWait()//等待信号
 {
      unsigned int i;
      while(ds);  
      while(~ds);
      i = 4;
      while(i > 0) i--;
}


bit readBit()//读一个bit位,一节数据共8个bit位,故后面会连续读到8次来实现读一个字节的数据
{
    unsigned int i;
    bit b;
    ds = 0;
    i++;   
    ds = 1; 
    i++; i++;  
    b = ds;
    i = 8; 
    while(i>0) i--;
    return b;//返回数据
}

unsigned char readByte() //读一个字节的数据
{
    unsigned int i;
    unsigned char j, dat;
    dat = 0;
    for(i=0; i<8; i++)//每一次读一位,一节数据共8位,读8次
    {
        j = readBit();
      
        dat = (j << 7) | (dat >> 1);
    }
    return dat;
}


void writeByte(unsigned char dat)//写一节数据
{
    unsigned int i;
    unsigned char j;
    bit b;
    for(j = 0; j < 8; j++)//每次写一位,写8次
    {
        b = dat & 0x01;//取最低位,从最低位泄气
        dat >>= 1; //右移一位   
        if(b)   
        {
           ds = 0;         
           i++; i++;//延时以产生时序  
           ds = 1;    
           i = 8;
           while(i>0) i--; //延时以产生时序 
        }
        else  
        {
          ds = 0;
          i = 8;
          while(i>0) i--;//延时以产生时序  
          ds = 1;
          i++; i++;//延时以产生时序
        }
   }
}


void sendChangeCmd()//发送指令
{
    dsInit();    
    dsWait();   
    delayMs(1);    
    writeByte(0xcc);//发送跳跃ROM指令(注意:当只有一只从机在总线上时,无论如何,
        //忽略ROM指令之后只能跟着发出一条暂存器指令【BEh】)
    writeByte(0x44);//发送温度转换指令
}

void sendReadCmd()//读操作
{
    dsInit();
    dsWait();
    delayMs(1);
    writeByte(0xcc);//发送跳跃ROM指令 
    writeByte(0xbe);//发送温度转换指令 
}


int getTmpValue()  //获取温度值
{
    unsigned int tmpvalue;
    int value; 
    float t;
    unsigned char low, high;
    sendReadCmd();
    
    low = readByte(); 
    high = readByte();
   
    tmpvalue = high;
    tmpvalue <<= 8;
    tmpvalue |= low;
    value = tmpvalue;
    
    t = value * 0.0625;
   
    value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
    return value;
}

void display(int v) //LCD1602显示内容设置
{
    unsigned char count;
    unsigned char datas[] = {0, 0, 0, 0, 0};
    unsigned int tmp = abs(v);
    datas[0] = tmp / 10000;
    datas[1] = tmp % 10000 / 1000;
    datas[2] = tmp % 1000 / 100;
    datas[3] = tmp % 100 / 10;
    datas[4] = tmp % 10;
    writeComm(0xc0+3);
    if(v < 0)
    {
        writeString("- ", 2);
   }
    else
    {
       writeString("+ ", 2);
    }
    if(datas[0] != 0)
    {
        writeData('0'+datas[0]);
    }
    for(count = 1; count != 5; count++)
    {
        writeData('0'+datas[count]);
        if(count == 2)
        {
            writeData('.');
        }
    }
}
/**//*****************************DS18B20*******************************/

void main()
{
    uchar table[] = "  xianzaiwendu: ";
    sendChangeCmd();
    init();
    writeComm(0x80);
    writeString(table, 16);//发送"  xianzaiwendu: "
    while(1)
    {
        delayMs(1000); //温度转换时间需要750ms以上
        writeComm(0xc0);
        display(getTmpValue());//通过LCD1602显示温度转换值
        sendChangeCmd();//发送转换指令
    }
}

最后希望我的分享对你有所帮助!敬请关注,持续更新!

考虑到一些读者需要相关资料和解决一些疑问,因此我新建立了一个学习交流群,我在群文件里上传了一些资料,需要的读者可以入群下载。

群中文件资料我会时常更新,主要资料是51单片机开发、32单片机开发、编程、嵌入式学习、算法控制等。

由于群中文件还在不断更新上传,有些方面的资料还不太完善,希望大家理解。若群中涉及违规行为,欢迎举报!

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小_扫地僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值