ds18b20应用程序实例分析

传感器

282人已加入

描述

  DS18B20,是一款强大的测温传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点,所以是开发中必不可少的一个芯片,为了方便大家上手

  DS18B20温度传感器是DALLAS公司生产的1-wire式单总线器件,具有线路简单,体积小的特点,用它组成的温度测量系统线路非常简单,只要求一个端口即可实现通信。温度测量范围在-55℃~+125℃之间,分辨率可以从9~12位选择,内部还有温度上、下限报警设置。每个DS18B20芯片都有唯一的序列号,所以可以利用多个DS18B20同时连接在同一条总线上,组成多点测温系统。但最多只能连接8个,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。

 DS18B20

  DS18B20 的初始化:

  根据 DS18B20 的通讯协议,主机(单片机)控制 DS18B20 完成温度转换必须经过三个步骤:每一次读写之前都要对 DS18B20 进行复位操作,复位成功后发送一条 ROM 指令,最后发送 RAM 指令,这样才能对 DS18B20 进行预定的操作。复位要求主 CPU 将数据线下拉 500 微秒,然后释放,当 DS18B20 收到信号后等待 16~60 微秒左右,后发出 60~240 微秒的存在低脉冲,主 CPU 收到此信号表示复位成功。

  (1) 先将数据线 DQ 置高电平“1”。

  (2) 延时(该时间要求的不是很严格,但是尽可能的短一点)

  (3) 数据线拉到低电平“0”。

  (4) 延时 750 微秒(该时间的时间范围可以从 480 到 960 微秒)。

  (5) 数据线拉到高电平“1”。

  (6) 延时等待(如果初始化成功则在 15 到 60 微妙时间之内产生一个由 DS18B20 所返回的低电平“0”。据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制)。

  (7) 若 CPU 读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(5)步的时间算起)最少要 480 微秒。

  (8) 将数据线再次拉高到高电平“1”后结束。

  初始化程序如下:

  uchar Init_DS18B20()

  {

  uchar status; //status 为 DS18B20 返回的状态

  DQ = 1;

  Delay(8);

  DQ = 0;

  Delay(90);

  DQ = 1;

  Delay(8);

  status=DQ;

  Delay(100);

  DQ = 1;

  return status;

  }

  DS18B20 应用举例(一)

  如下图所示:DQ 通过 4.7K 上拉电阻外接正电源(由于单总线为开漏所以需要外接一个 4.7K 的上拉电阻),并连接单片机 P3.3 口。

  本例中,1602LCD 显示 DS18B20 所测量的外部温度,调节 DS18B20 模拟改变外界温度时,新的温度将刷新显示在 LCD 上

  DS18B20

  C 程序如下:

  由于本例仅保存一位小数,温度小数位对照表 df_Table[]将 0000~1111 对应的 16 个不同的小数进行四舍五入,例如,当读取的温度低字节低 4 位为 0101 时,对应的温度应为 2 -2 +2-4 =0.3125≈0.3,因此数组第 5 个元素(对应 0101)的值为 3;又如,如果低 4 位为 0110,对应的温度为 2 -2 +2-3 =0.375≈0.4,因此,数组第 6 个元素(对应 0110)取值为 4。

  #include #include

  #define uint unsigned int

  #define uchar unsigned char

  #define delay4us() {_nop_();_nop_();_nop_();_nop_();} //12MHZ 系统频率下,延时 4us

  sbit DQ = P3^3;

  sbit LCD_RS = P2^0;

  sbit LCD_RW = P2^1;

  sbit LCD_EN = P2^2;

  uchar code Temp_Disp_Title[]={“Current Temp : ”}; //1602 液晶第一行显示内容

  uchar Current_Temp_Display_Buffer[]={“ TEMP: ”}; //1602 液晶第二行显示内容

  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; //DS18B20 正常标志

  void DelayXus(uint x) //延时 1

  {

  uchar i;

  while(x--)

  {

  for(i=0;i《200;i++);

  }

  }

  bit LCD_Busy_Check() //LCD 忙标志,返回值为 1602LCD 的忙标志位,为 1 表示忙

  {

  bit result;

  LCD_RS = 0;

  LCD_RW = 1;

  LCD_EN = 1;

  delay4us();

  result = (bit)(P0&0x80);

  LCD_EN=0;

  return result;

  }

  void Write_LCD_Command(uchar cmd) //1602LCD 写指令函数

  {

  while(LCD_Busy_Check());

  LCD_RS = 0;

  LCD_RW = 0;

  LCD_EN = 0; _

  nop_();

  _nop_();

  P0 = cmd;

  delay4us();

  LCD_EN = 1;

  delay4us();

  LCD_EN = 0;

  }

  void Write_LCD_Data(uchar dat) //1602LCD 写数据函数

  {

  while(LCD_Busy_Check());

  LCD_RS = 1;

  LCD_RW = 0;

  .LCD_EN = 0;

  P0 = dat; delay4us();

  LCD_EN = 1;

  delay4us();

  LCD_EN = 0;

  }

  void LCD_Initialise() //1602LCD 初始化

  {

  Write_LCD_Command(0x01);

  DelayXus(5);

  Write_LCD_Command(0x38);

  DelayXus(5);

  Write_LCD_Command(0x0c);

  DelayXus(5);

  Write_LCD_Command(0x06);

  DelayXus(5);

  {

  void Set_LCD_POS(uchar pos) //1602LCD 设置显示位置

  }

  Write_LCD_Command(pos|0x80);

  }

  void Delay(uint x) //延时 2

  {

  while(x--);

  }

  uchar Init_DS18B20() //初始化(或者说复位)DS18B20

  {

  uchar status;

  DQ = 1;

  Delay(8);

  DQ = 0;

  Delay(90);

  DQ = 1;

  Delay(8);

  status=DQ;

  Delay(100);

  DQ = 1;

  return status;

  }

  uchar ReadOneByte() //从 DS18B20 读一字节数据

  {

  uchar i,dat=0;

  DQ = 1;

  _nop_();

  for(i=0;i《8;i++)

  {

  DQ = 0;

  dat 》》= 1;

  DQ = 1;

  _nop_();

  _nop_();

  if(DQ)

  dat |= 0X80;

  Delay(30);

  DQ = 1;

  }

  return dat;

  void WriteOneByte(uchar dat) //从 DS18B20 写一字节数据

  {

  uchar i;

  for(i=0;i《8;i++)

  {

  DQ = 0;

  DQ = dat& 0x01;

  Delay(5);

  DQ = 1; dat 》》= 1;

  }

  }

  void Read_Temperature() //从 DS18B20 读取温度值

  {

  if(Init_DS18B20()==1) //DS18B20 故障

  DS18B20_IS_OK=0;

  else

  {

  WriteOneByte(0xcc); //跳过序列号命令

  WriteOneByte(0x44); //启动温度转换命令

  Init_DS18B20(); //复位 DS18B20(每一次读写之前都要对 DS18B20 进行复位操作)

  WriteOneByte(0xcc); //跳过序列号命令

  WriteOneByte(0xbe); //读取温度寄存器

  Temp_Value[0] = ReadOneByte(); //读取温度低 8 位(先读低字节,再读高字节,)

  Temp_Value[1] = ReadOneByte();//读取温度高 8 位 (每次只能读一个字节) DS18B20_IS_OK=1; //DS18B20 正常

  }

  }

  void Display_Temperature() //在 1602LCD 上显示当前温度

  {

  uchar i;

  uchar t = 150, ng = 0; //延时值与负数标志

  if((Temp_Value[1]&0xf8)==0xf8) //高字节高 5 位如果全为 1,则为负数,为负数时取反

  { //加 1,并设置负数标志为 1

  Temp_Value[1] = ~Temp_Value[1];

  Temp_Value[0] = ~Temp_Value[0]+1;

  if(Temp_Value[0]==0x00) //若低字节进位,则高字节加 1

  Temp_Value[1]++;

  ng = 1; //设置负数标志为 1

  }

  Display_Digit[0] = df_Table[Temp_Value[0]&0x0f]; //查表得到温度小数部分

  }

  }

  //获取温度整数部分(低字节低 4 位清零,高 4 位右移 4 位)+(高字节高 5 位清零, //低三位左移 4 位)

  CurrentT = ((Temp_Value[0]&0xf0)》》4) | ((Temp_Value[1]&0x07)《《4);

  / //将温度整数部分分解为 3 位待显示数字

  Display_Digit[3] = CurrentT/100;

  Display_Digit[2] = CurrentT%100/10;

  Display_Digit[1] = CurrentT%10;

  //刷新 LCD 缓冲 //加字符 0 是为了将待数字转化为字符显示

  Current_Temp_Display_Buffer[11] = Display_Digit[0] + ‘0’;

  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’;

  if(Display_Digit[3] == 0) //高位为 0 时不显示

  Current_Temp_Display_Buffer[7] = ‘ ’;

  if(Display_Digit[2] == 0&&Display_Digit[3]==0) //高位为 0,且次高位为 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_LCD_POS(0x00); //第一行显示标题

  for(i=0;i《16;i++)

  {

  Write_LCD_Data(Temp_Disp_Title[i]);

  }

  Set_LCD_POS(0x40); //第二行显示当前温度

  for(i=0;i《16;i++)

  {

  Write_LCD_Data(Current_Temp_Display_Buffer[i]);

  }

  //显示温度符号

  Set_LCD_POS(0x4d);

  Write_LCD_Data(0x00);

  Set_LCD_POS(0x4e);

  Write_LCD_Data(‘C’);

  }

  void main() //主函数

  {

  LCD_Initialise();

  Read_Temperature();

  Delay(50000);

  Delay(50000);

  while(1)

  {

  Read_Temperature();

  if(DS18B20_IS_OK)

  Display_Temperature();

  DelayXus(100);

  }

  }

  Proteus 仿真运行结果如下:

  DS18B20

  DS18B20的应用实例二

  #include《reg51.h》

  sbit DQ=P3^0;

  sbit d1=P2^0;

  sbit d2=P2^1;

  #define uchar unsigned char

  #define uint unsigned int

  uchar temp_value;

  uchar code table[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};

  void delay_18B20(uint i)

  {

  while(i--);

  }

  void Init_DS18B20(void)

  {

  uchar x=0;

  DQ = 1; //DQ复位

  delay_18B20(8); //稍做延时

  DQ = 0; //单片机将DQ拉低

  delay_18B20(80); //精确延时 大于 480us

  DQ = 1; //拉高总线

  delay_18B20(14);

  x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败

  delay_18B20(20);

  }

  uchar ReadOneChar(void)

  {

  uchar i=0;

  uchar dat = 0;

  for (i=8;i》0;i--)

  {

  DQ = 0; // 给脉冲信号

  dat》》=1;

  DQ = 1; // 给脉冲信号

  if(DQ)

  dat|=0x80;

  delay_18B20(4);

  }

  return(dat);

  }

  void WriteOneChar(uchar dat)

  {

  uchar i=0;

  for (i=8; i》0; i--)

  {

  DQ = 0;

  DQ = dat&0x01;

  delay_18B20(5);

  DQ = 1;

  dat》》=1;

  }

  }

  void ReadTemp(void)

  {

  uchar a=0;

  uchar b=0;

  uchar t=0;

  Init_DS18B20();

  WriteOneChar(0xCC); // 跳过读序号列号的操作

  WriteOneChar(0x44); // 启动温度转换

  delay_18B20(100); // this message is wery important

  Init_DS18B20();

  WriteOneChar(0xCC); //跳过读序号列号的操作

  WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度

  delay_18B20(100);

  a=ReadOneChar(); //读取温度值低位

  b=ReadOneChar(); //读取温度值高位

  temp_value=b《《4;

  temp_value+=(a&0xf0)》》4;

  }

  void display (uchar num0,uchar num1)

  { P2=0XFD;

  P0=table[num1];

  delay_18B20(20);

  P2=0XFE;

  P0=table[num0];

  delay_18B20(20);

  }

  main()

  {

  uchar a ,b ;

  while(1)

  {

  ReadTemp();

  b=temp_value/10; //十位

  a=temp_value%10; //个位

  display(b,a);

  }

  }

  DS18B20

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分