找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4890|回复: 6
收起左侧

ds18b20温度感应详解

[复制链接]
ID:68618 发表于 2014-11-11 19:04 | 显示全部楼层 |阅读模式
DS18B20是一种常用的温度传感器,可以实现多点网络式测量,这里简单介绍单个ds18b20的使用。
DS18B20看起来像一个三极管,有三个引脚,1:地,2:数据端,3:电源,DS18B20的通信方式有点特别,仅靠一根线进行通信,而且多个DS18B20也是连在一个线上的,所以通信协议仅靠高低电平实现,而且速度较慢,因为传输数据较少,所以时间还是可以忍受。


简单起见,这里介绍单个DS18B20的使用方法,忽略地址匹配等方法,下面结合程序,说明一下主流程:
unsigned int ds18b20_read_temperature(void)
{
  unsigned int temperature;
  ds18b20_init();  //初始化(复位)
  ds18b20_write_byte(0xCC);  //发送命令,跳过ROM
  ds18b20_write_byte(0x44);  //温度转换
  delayms(1000);  //给必要的转换时间
  ds18b20_init();   //DS1302 复位
  ds18b20_write_byte(0xCC);  //跳过ROM
  ds18b20_write_byte(0xbe);  //读取RAM
  temperature = ds18b20_read_byte(); //读低八位,LS Byte, RAM0
  temperature |= ds18b20_read_byte() << 8; //读高八位,MS Byte, RAM1
  return temperature*0.0625; //0.0625=xx, 0.625=xx.x, 6.25=xx.xx
}

很简单,启动温度转换,等待,读取结果。


下面介绍DS18B20的单线通信方式:
这个要细细研究手册的时序图,才能写好程序。

1.DS18B20的复位:


总线先给一个480us的低电平,等待15-60us,DS18B20会有一个60-240us的低电平响应,注意用时候可能因为软件或硬件的问题,并没有使DS18B20成功初始化,这样程序会进入无限等待的死循环里,这里为了防止死循环的发生,使用最大延时限制,一旦延时到且初始化未成功,就重新初始化。
程序如下:
void ds18b20_init(void)
{
  int i;
again:        //这里为了方便,用了一个C语言的禁忌指令:goto label
      TD = 1; //T 为输出状态
      TO = 0; //输出低电平
      delayus(500); //延迟480~960 us
      TO = 1; //释放总线
      TD = 0; //DQ 位输状入态
      
#define MAX 480   //定义一个最大延时数,防止死循环
      
      for(i=MAX;i>0;i--)
      {
        if(!TI)  break;//检测到低电平,跳到下一步
      }
      if(i == 0) goto again;//最大延时到,重新检测
      
      for(i=MAX;i>0;i--)
      {
        if(TI)  break;//检测到高电平,跳到下一步
      }
      if(i == 0) goto again;//最大延时到,重新检测
}

2.向DS18B20写一位:
如果写0,则给60~120us的低电平;如果写1,先给至少1us的低电平,然后给高电平,直至60us。
void write_bit(char b)
{
  TD = 1;
  
  TO = 0;//拉低总线
  delayus(2); //至少1us
  
  TO = !!b;   //  !!是为了把非零数转换 为1
  delayus(58); //保证60us
  TO = 1; //释放总线
}

3.读DS18B20一位:
先给至少1us的低电平,然后在15us内读取,高为1,低为0,在等待,直至60us。
char read_bit(void)
{
  char b;
  TD = 1;//置位输出
  
  TO = 0;//拉低总线,至少1us
  delayus(2);
  TO = 1;
  
  TD = 0;//置位输入
  delayus(4);//必须在15us内读取
  b = TI;
  delayus(54);
  
  TD = 1;//置位输出
  TO = 1;//释放总线
  return b;
}



下面是完整的程序:
编译器:IAR
单片机:ATmega32 或 16

#include "main.h"
//定义 T 引脚
#define TD DDRC_Bit7
#define TO PORTC_Bit7
#define TI PINC_Bit7
//根据时序图,先给至少1us的低电平,
//写1则拉高       直至60us
//写0则继续保持   直至60us
void write_bit(char b)
{
  TD = 1;
  
  TO = 0;//拉低总线
  delayus(2); //至少1us
  
  TO = !!b;   //  !!是为了把非零数转换 为1
  delayus(58); //保证60us
  TO = 1; //释放总线
}
void ds18b20_write_byte(char val)
{
  char i;
  for(i=0;i<8;i++)
  {
    write_bit( val&(1<<i) );
  }
}
//根据时序图,先给至少1us的低电平,
//然后在15us内读取
//高为1       直至60us
//低为0       直至60us
char read_bit(void)
{
  char b;
  TD = 1;//置位输出
  
  TO = 0;//拉低总线,至少1us
  delayus(2);
  TO = 1;
  
  TD = 0;//置位输入
  delayus(4);//必须在15us内读取
  b = TI;
  delayus(54);
  
  TD = 1;//置位输出
  TO = 1;//释放总线
  return b;
}
char ds18b20_read_byte(void)
{
  char i;
  char value=0; //读出温度
  for(i=0;i<8;i++)
  {
    value |= read_bit() << i;
  }
  return(value);
}
//根据时序图,先给一个480~960us的低电平,然后释放总线等待DS18B20响应(一个低脉冲)
//为了稳定性,使用延时循环以防止了死循环的发生
void ds18b20_init(void)
{
  int i;
again:        //这里为了方便,用了一个C语言的禁忌指令:goto label
      TD = 1; //T 为输出状态
      TO = 0; //输出低电平
      delayus(500); //延迟480~960 us
      TO = 1; //释放总线
      TD = 0; //DQ 位输状入态
      
#define MAX 480   //定义一个最大延时数,防止死循环
      
      for(i=MAX;i>0;i--)
      {
        if(!TI)  break;//检测到低电平,跳到下一步
      }
      if(i == 0) goto again;//最大延时到,重新检测
      
      for(i=MAX;i>0;i--)
      {
        if(TI)  break;//检测到高电平,跳到下一步
      }
      if(i == 0) goto again;//最大延时到,重新检测
}
unsigned int ds18b20_read_temperature(void)
{
  unsigned int temperature;
  ds18b20_init();
  ds18b20_write_byte(0xCC); //跳过ROM
  ds18b20_write_byte(0x44); //温度转换
  delayms(1000);//给必要的转换时间
  ds18b20_init(); //DS1302 复位
  ds18b20_write_byte(0xCC); //跳过ROM
  ds18b20_write_byte(0xbe); //读取RAM
  temperature = ds18b20_read_byte(); //读低八位,LS Byte, RAM0
  temperature |= ds18b20_read_byte() << 8; //读高八位,MS Byte, RAM1
  return temperature*0.0625; //0.0625=xx, 0.625=xx.x, 6.25=xx.xx
}
/*
int main( void )
{
  unsigned int Temp;
  while(1)
  {
  Temp = ds18b20_read_temperature(); //调用读取温度函数
// delayus(100); //稍微延迟
  }
}
*/

回复

使用道具 举报

ID:7485 发表于 2014-11-13 18:46 | 显示全部楼层
游客 183.69.216.x 发表于 2014-11-12 11:26
比较详细,不错,18B20最不好弄的是时间,比如1US的延时程序,不同的IC不同的晶振,没有示波器的话,不太好 ...

没有这么难吧?
只要按照资料上给出的时间隙编写程序不会有问题的。时间隙的弹性还是比较大的。最好是使用汇编写这一段。
回复

使用道具 举报

ID:68356 发表于 2014-11-13 22:16 | 显示全部楼层
学习了,收藏
回复

使用道具 举报

ID:67678 发表于 2014-11-13 23:08 | 显示全部楼层
学习了
谢谢
回复

使用道具 举报

ID:75749 发表于 2015-3-30 23:56 | 显示全部楼层
支持一下
回复

使用道具 举报

ID:111517 发表于 2016-4-3 12:57 | 显示全部楼层
请问下楼主那个读“0”操作中的45us是做什么用的,可以不用吗,读取过后直接用个大于1us的延时(即两个读时序的恢复期),然后进行下次的读操作可以吗??
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表