STM32
直播中

一说就是错

12年用户 532经验值
私信 关注
[问答]

DS18B20的工作原理是什么?通讯方式有哪些?

DS18B20的工作原理是什么?通讯方式有哪些?

回帖(1)

顾鸿兰

2021-11-25 11:12:20
  一、前言

  继上次发布的光照传感器讲解,这次继续讲一些简单的适合大学生学习使用的传感器。这次要讲的是一款温度传感器,想要完整代码工程的,可以在文章末尾的链接下载。
  二、芯片介绍

  1、简介
DS18B20是一款数字型温度传感器,这款传感器已经有长的历史了,驱动方式简单,很适合初学者使用,具体的我就不多说了,很多人应该都是知道这个传感器的。
2、引脚定义
  [tr]引脚名称说明[/tr]
1GND供电电源负极
2DQ数据输入输出引脚(和单片机IO口相连的时候一定要接上拉电阻)
3VCC供电电源正极
3、通讯方式
DS18B20用的是单总线方式,单片机给DQ引脚输出一定规则的时序信号即可配置和驱动DS18B20,同样的,单片机按照时序接收DS18B20发送的数据即可得到温度数据。
4、工作原理
DS18B20通过传感威廉希尔官方网站 把温度转换成对应的电压信息,然后转换成数字信号,再把温度相关的数据存到自身的寄存器里面,单片机去读取这些数据,就可以知道当前的温度了。简单的说就是把模拟信号转换成数字信号,然后把这些数据存起来交给单片机,大概的原理是这样,如果你想继续深入了解,可以去找一下相关的文章,关于这方面的介绍有很多。
  三、编程讲解

  1、DS18B20驱动程序

//单片机只需要用一个普通的IO口和DS18B20的DQ引脚相连,然后控制这个IO口输出高低电平即可


//复位DS18B20
//作用:复位
void DS18B20_Rst(void)          
{                 
        DS18B20_IO_OUT(); //把单片机的IO口配置为输出
    DS18B20_DQ_OUT=0; //拉低DQ
    delay_us(750);    //拉低750us,这个时间是根据DS18B20本身的规则定的,可以在数据手册找到相关介绍
    DS18B20_DQ_OUT=1; //拉高DQ
        delay_us(15);     //15US
}


//等待DS18B20的回应
//作用:检查单片机和DS18B20的通讯是否正常
//返回1:未检测到DS18B20的存在(可能是DQ引脚没有上拉电阻,通讯的时序不对,芯片损坏等原因)
//返回0:存在
u8 DS18B20_Check(void)           
{   
        u8 retry=0;
        DS18B20_IO_IN();//把IO口配置为输入,目的是为了接收DS18B20发过来的数据         
    while (DS18B20_DQ_IN&&retry<200)//如果IO口是低电平,则是正常的,否则一直进while循环
        {
                retry++;
                delay_us(1);
        };         
        if(retry>=200)
        {//通讯有误,返回1
                return 1;
        }
        else
        {//正常
                retry=0;
        }
    while (!DS18B20_DQ_IN&&retry<240)//继续读取电平,如果IO口是高电平,则是正常的
        {
                retry++;
                delay_us(1);
        };
        if(retry>=240)
        {//通讯有误,返回1
                return 1;
        }            
        return 0;//通讯正常,返回0
}


//从DS18B20读取一个位
//作用:读取一个位数据,重复调用该函数可以把温湿度数据读出来
//返回值:1/0
u8 DS18B20_Read_Bit(void)                          // read one bit
{
          u8 data;
        DS18B20_IO_OUT();//单片机输出一个由低到高的上升沿脉冲给DS18B20
        DS18B20_DQ_OUT=0;
        delay_us(2);
        DS18B20_DQ_OUT=1;
        DS18B20_IO_IN();//把IO口配置为输入,读取电平
        delay_us(12);
        if(DS18B20_DQ_IN)//如果是高电平,则DS18B20输出的数据是'1',否则为'0'
                data=1;
          else
                  data=0;         
        delay_us(50);           
          return data;
}


//从DS18B20读取一个字节
//作用:连续读8个位,并合成一个字节数据
//返回值:读到的数据
u8 DS18B20_Read_Byte(void)    // read one byte
{        
    u8 i,j,dat;
    dat=0;
        for (i=1;i<=8;i++)
        {
        j=DS18B20_Read_Bit();//连续调用8次
        dat=(j<<7)|(dat>>1);//每次读取到1个位的数据后左移1位,读取完8个位的数据之后就可以合成1个字节了
    }                                                    
    return dat;//返回合成的1字节数据
}


//写一个字节到DS18B20
//作用:写数据到DS18B20,调用这个函数可以发送指令控制DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)     
{            
    u8 j;
    u8 testb;
        DS18B20_IO_OUT();//SET PA0 OUTPUT;
    for (j=1;j<=8;j++)
        {
        testb=dat&0x01;//把传进来的这个数据的最高位提取出来
        dat=dat>>1;//dat的数据左移1位,作用是把次高位移到最高位
        if (testb) //如果最高位数据为'1'
        {
            DS18B20_DQ_OUT=0;// Write 1
            delay_us(2);                           
            DS18B20_DQ_OUT=1;//输出60us高电平,相当于告诉DS18B20要传的数据是'1'
            delay_us(60);            
        }
        else //如果最高位数据为'0'
        {
            DS18B20_DQ_OUT=0;//输出60us低电平,相当于告诉DS18B20要传的数据是'0'
            delay_us(60);            
            DS18B20_DQ_OUT=1;
            delay_us(2);                          
        }
    }
}


//开始温度转换
//作用:从DS18B20中读取温度数据
void DS18B20_Start(void)// ds1820 start convert
{                                                                 
  DS18B20_Rst();//复位   
  DS18B20_Check();//检查单片机和DS18B20的通讯是否正常         
  DS18B20_Write_Byte(0xcc);//寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
  DS18B20_Write_Byte(0x44);//0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS
}
//初始化DS18B20的IO口DQ 同时检测DS18B20的存在
//返回1:不存在
//返回0:存在             
u8 DS18B20_Init(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);         //使能PORTA口时钟
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;                                //PORTA0 推挽输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                   
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);


        GPIO_SetBits(GPIOA,GPIO_Pin_0);    //输出1


        DS18B20_Rst();//复位


        return DS18B20_Check();
}  
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
    u8 temp;
    u8 TL,TH;
        short tem;
    //DS18B20_Start (); //开始采集温度
    DS18B20_Rst();//复位
    DS18B20_Check();//检查单片机和DS18B20通讯是否正常         
    DS18B20_Write_Byte(0xcc);//寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
    DS18B20_Write_Byte(0xbe);//0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS   
    TL=DS18B20_Read_Byte(); //读取数据低字节  
    TH=DS18B20_Read_Byte(); //读取数据高字节
                      
    if(TH>7)
    {
        TH=~TH;
        TL=~TL;
        temp=0;//温度为负  
    }
    else
    {
            temp=1;//温度为正       
    }            
    tem=TH;//获得高字节数据
    tem<<=8;//高字节位左移8位   
    tem+=TL;//左移的高8位加上低8位合成一个16位数据
    tem=(float)tem*0.625;//从DS18B20读取到的2个字节的数据还不是温度值,需要转换,转换公式参考数据手册     
        if(temp)
        {
                return tem; //返回温度值
        }
        else
        {
                return -tem;   
        }
}
2、main函数

int main()
{  
        short temperature;   
        uart_init(115200);                 //串口初始化为115200
        LED_Init();                                  //初始化与LED连接的硬件接口
        OLED_Init();            //OLED初始化
        OLED_Clear();           //OLED清屏
        while(DS18B20_Init())        //DS18B20初始化       
        {
            OLED_ShowString(50,2,"error",12);//DS18B20通讯有问题
        }
        while(1)
        {       
            //读取温度               
                temperature=DS18B20_Get_Temp();       
                if(temperature<0)//温度低于0
                {               
                        OLED_ShowString(50,4,"-",16);   //显示负号
                        temperature=-temperature;            //转为正数
                }
                else //温度大于0
                {
                        OLED_ShowString(50,4," ",16);        //不显示负号,也不显示正号
                }         
                OLED_ShowCHinese(0,4,0);//显示中文字体“温”
                OLED_ShowCHinese(16,4,1);//显示中文字体“度”
                OLED_ShowString(32,4,":",16);
                OLED_ShowNum(60,4,temperature/10,2,16); //显示整数部分
                OLED_ShowString(80,4,".",16);
                   OLED_ShowNum(88,4,temperature%10,1,16);        //显示小数部分
                OLED_ShowCHinese(100,4,9);//显示“℃”
        }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分