8、单总线与DB18B20实现温度的测量

1、单总线(1-Wire)通信的基本概念

在串行通信系统中通常具备:
时钟信号线,数据信号线,控制信号线,设备电源线

  • UART:VCC GND TXD(串口的发送引脚) RXD(串口的接收引脚)
  • USART:VCC GND TXD RXD SCK(时钟信号)
  • SPI:VCC GND CS(片选引脚) MOSI MISO SCK
  • I2C:VCC GND SDA(串行数据线) SCK(串行时钟线)

优缺点:

  1. 总线的驱动能力较差,超过一定数量会不稳定
  2. 距离不长,1-Wire总线更适合中短距离低速
  3. 由于硬件集成一线比较简单,软件的复杂度上升

2、DS18B20温度传感器的介绍

  • 1、外形
    在这里插入图片描述
  • 2、供电方式
    寄生方式供电
    在这里插入图片描述
    在这里插入图片描述
    外部供电方式(需要考虑压降)
    在这里插入图片描述
  • 3、内部电路
    内部含有单元电源单元,ROM单元,存储器逻辑控制单元,温度转换单元,高速暂存器单元等
    在这里插入图片描述
    DS18B20只能去读而不能写,具备高温报警,-10°-40°
1)ROM操作指令

DS18B20设备中有关ROM操作的指令一共有5个,如下所示:

在这里插入图片描述
(读取和跳过用得比较多,其他的用得比较少)

2)功能性指令

除了ROM指令在之外,还有功能性的指令
在这里插入图片描述
(主要用的是温度转换和读暂存器)

3、DS18B20 的数据格式及转换

  1. 转换分配率问题
    在配置寄存器中的位 6 和位 5 两个位来控制
    在这里插入图片描述
  2. 温度值的存放问题
    在高字节中的高 5 位是符号位,图中用 S 表示。如果温度值是正数,则 S 位均为 0,若为负数,则 S 位均为 1
    在这里插入图片描述
  • 问题1:符号位为什么要5个?

没有必要占用这么多位,其可测量的温度范围比较窄,为了数据好处理,所以用了5个符号位。

  • 问题2:抛开符号位,其他的全部为只有11位?

将高位的5为结合成了一个符号位,也就是12位的分辨率指的是S位+其余的11位。
位0-位3部分是小数部分,位4-位19是整数部分,位11-位15是符号位。对于12位的转换分辨率,温度传感器的所以位都是有效的;对于11为的转换分辨率,位0是无效的;对于10为的分辨率,位0和位1是无效的;对于9位的分辨率,位2,位1,位0是无效的。

  • 问题3:负数温度如何处理?

负数温度按照补码来操作,所以如果是-55°需要存储,其正确的答案不是0b1111101101110000也就是0xFB70,而是按照补码来显示为0b1111110010010000也就是0xFC90。(补码=反码+1,反码=源码取反)

  • 问题4:温度如何转换为正确的摄氏温度?

实际温度 = 份数 * 最小的分辨率

温度数值转换格式的例子:
在这里插入图片描述
高温阈值和低温阈值的设置(少用)
在这里插入图片描述
当实际采样测量的温度值超过高温限值或者是低于低温阈值的时候,这时候DS18B20设备会发出报警信号。

4、 DS18B20 的时序图

DS18B20 设备采用了严格的 1-Wire 单总线通信协议来保证数据的完整性和有效性。第一是发送初始化时序,第二是发送 ROM 命令,第三是发送功能命令。
在这里插入图片描述

  • 问题:如何写命令给从机,也就是如何让从机知道我们是写 1 还是写 0,才能将一个 1byte的数据发送过去?

对于一个字节的数据,有高低位之分,而数据的发送要先发低位,再发高位。注意好写 0 和写 1 的时间隙。在正确的时间隙中操作就是主机与从机之间正确通信的保障。

1)主机的两个写入操作
  • 操作1:写1的时间隙
    在这里插入图片描述
  • 操作2:写0的时间隙
    在这里插入图片描述
2)从机的两个应答操作(主机读0读1)

在这里插入图片描述
注意要注意好时间,主机的采样一定要是15微秒以内

在这里插入图片描述
在这里插入图片描述

5、 DS18B20 的操作流程

  1. 复位
    首先我们必须对 ds18b20 芯片进行复位,复位就是由控制器(单片机)给 ds18b20 单
    总线至少 480uS 的低电平信号。当 18B20 接到此复位信号后则会在 15~60uS 后回发一个芯
    片的存在脉冲。
  2. 存在脉冲
    在复位电平结束之后,控制器应该将数据单总线拉高,以便于在 15~60uS 后接收存在
    脉冲,存在脉冲为一个 60~240uS 的低电平信号。至此,通信双方已经达成了基本的协议,
    接下来将会是控制器与 18B20 间的数据通信。如果复位低电平的时间不足或是单总线的电
    路断路都不会接到存在脉冲,在设计时要注意意外情况的处理。
  3. 控制器发送 ROM 指令
    双方打完了招呼之后最要将进行交流了,ROM 指令共有 5 条,每一个工作周期只能发一
    条,ROM 指令分别是读 ROM 数据、指定匹配芯片、跳跃 ROM、芯片搜索、报警芯片搜索。ROM
    指令为 8 位长度,功能是对片内的 64 位光刻 ROM 进行操作。其主要目的是为了分辨一条总
    线上挂接的多个器件并作处理。诚然,单总线上可以同时挂接多个器件,并通过每个器件
    上所独有的 ID 号来区别,一般只挂接单个 18B20 芯片时可以跳过 ROM 指令(注意:此处指
    的跳过 ROM 指令并非不发送 ROM 指令,而是用特有的一条“跳过指令”)。ROM 指令在下
    文有详细的介绍。
  4. 控制器发送存储器操作指令
    在 ROM 指令发送给 18B20 之后,紧接着(不间断)就是发送存储器操作指令了。操作
    指令同样为 8 位,共 6 条,存储器操作指令分别是写 RAM 数据、读 RAM 数据、将 RAM 数据
    复制到 EEPROM、温度转换、将 EEPROM 中的报警值复制到 RAM、工作方式切换。存储器操作
    指令的功能是命令 18B20 作什么样的工作,是芯片控制的关键。
  5. 执行或数据读写
    一个存储器操作指令结束后则将进行指令执行或数据的读写,这个操作要视存储器操
    作指令而定。如执行温度转换指令则控制器(单片机)必须等待 18B20 执行其指令,一般
    转换时间为 500uS。如执行数据读写指令则需要严格遵循 18B20 的读写时序来操作。
    需要注意:
    换存储器操作指令、等待 500uS 温度转换时间。紧接着执行第二个周期为复位、跳过
    ROM 指令、执行读 RAM 的存储器操作指令、读数据(最多为 9 个字节,中途可停止,只读
    简单温度值则读前 2 个字节即可)。其它的操作流程也大同小异,在此不多介绍。

6、参考代码

/****************************************************************/
//设备初始化时序产生函数DS18B20_reset(),无形参和返回值
/****************************************************************/
void DS18B20_reset(void)
{
  u8 x;
  DS18B20_DQ_DDR(1);
  DS18B20_DQ=1;
  delay(1700);
  DS18B20_DQ=0;
  delay(1700);
  DS18B20_DQ=1;
  delay(65);
  DS18B20_DQ_DDR(0);
  delay(65);
  x=PI_IDR_IDR4;
  printf("|[1].开始检测DS18B20......\r\n");
  while(x);
  printf("|[2].DS18B20检测成功\r\n");
  delay(1150);//控制器等待至少480us
}

/****************************************************************/
//设备DQ引脚方向性配置函数DS18B20_DQ_DDR(),有形参ddr无返回值
/****************************************************************/
void DS18B20_DQ_DDR(u8 ddr)
{
  if(ddr==1)	//配置为输出方式
  {
    PI_DDR_DDR4=1;
    PI_CR1_C14=1;
    PI_CR2_C24=0;
  }
  else			//配置为输入方式
  {
    PI_DDR_DDR4=0;
    PI_CR1_C14=1;
    PI_CR2_C24=0;
  }
}

/****************************************************************/
//设备初始化函数DS18B20_init(),无形参和返回值
/****************************************************************/
void DS18B20_init(void)
{
  DS18B20_reset();
  delay(1000);
  DS18B20_Wbyte(0xCC);//写ROM指令(跳过ROM)
  DS18B20_Wbyte(0x44);//写功能指令(温度转换)
  printf("|[3].启用温度转换\r\n");
}

/****************************************************************/
//设备写一个字节函数DS18B20_Wbyte(),有形参xbyte无返回值
/****************************************************************/
void DS18B20_Wbyte(u8 xbyte)
{
  u8 i,x=0;
  DS18B20_DQ_DDR(1);
  for(i=0;i<8;i++)	//8次循环实现逐位写入
  {
    x=xbyte & 0x01; //从最低位取值到最高位
    if(x)			//写“1”
    {
      DS18B20_DQ=0;
      delay(30);
      DS18B20_DQ=1;
      delay(100);
      DS18B20_DQ=1;
    }
    else			//写“0”
    {
      DS18B20_DQ=0;
      delay(30);
      DS18B20_DQ=0;
      delay(100);
      DS18B20_DQ=1;
    }
    xbyte=xbyte>>1;	//右移一位实现逐位移出
  }
}

/****************************************************************/
//设备读字节函数DS18B20_Rbyte(),无形参有返回值rbyte
/****************************************************************/
u8 DS18B20_Rbyte(void)
{
  u8 rbyte=0,i=0,tempbit=0;
  for(i=0;i<8;i++)	//8次循环实现逐位拼合
  {
    tempbit=DS18B20_Rbit();	//读取单个位
    rbyte=rbyte>>1;			//右移实现将高低位排列
    rbyte=rbyte|tempbit;	//或运算移入数据
  }
  return rbyte;
}

/****************************************************************/
//设备读取单个位函数DS18B20_Rbit(),无形参有返回值rbit
/****************************************************************/
u8 DS18B20_Rbit(void)
{
  u8 rbit=0,x=0;
  DS18B20_DQ_DDR(1);
  DS18B20_DQ=0;
  delay(30);
  DS18B20_DQ=1;
  DS18B20_DQ_DDR(0);
  delay(20);
  x=PI_IDR_IDR4;
  if(x)
    rbit=0x80;
  delay(150);
  return rbit;
}

/****************************************************************/
//设备温度获取和转换函数DS18B20_get_Temperature(),无形参和返回值
/****************************************************************/
void DS18B20_get_Temperature(void)
{
  u8 msb_byte=0,lsb_byte=0;	//msb是温度值高位,lsb是温度值低位
  DS18B20_reset();			//初始化时序
  delay(1000);				//等待初始化稳定
  DS18B20_Wbyte(0xCC);		//写ROM指令(跳过ROM)
  DS18B20_Wbyte(0xBE);		//写功能指令(读暂存器)
  delay(1000);				//等待配置稳定
  printf("|[4].开始温度读取操作\r\n");
  lsb_byte=DS18B20_Rbyte();	//读取第一个低位数据字节
  msb_byte=DS18B20_Rbyte();	//读取第二个高位数据字节
  Tem_u16=msb_byte;			
  Tem_u16=Tem_u16<<8;		
  Tem_u16=Tem_u16|lsb_byte;	
  if(Tem_u16<=0x07FF)		//温度值正负判断
  {
    flag=1;					//温度值为正(最高能测到125摄氏度)
    Tem_f=Tem_u16*0.0625;	//乘以0.0625最小分辨值得到12位温度实际值
    Tem_u16=(u16)(Tem_f+0.5);//4舍5入得到温度整数值
  }
  else
  {
    flag=0;					//温度值为负(最低能测到-55摄氏度)
    Tem_u16=~(Tem_u16-1);	//此时数据是补码形式
    //采用“补码-1”再按位取反的方法得到对应原码
    Tem_f=Tem_u16*0.0625;//乘以0.0625最小分辨值得到12位温度实际值
    Tem_u16=(u16)(Tem_f+0.5);//4舍5入得到温度整数值
  }
}

曾经做过一个单片机课设,实现DB18B20获取温度然后使用LCD1602显示,并且串口打印出来,有兴趣的可以下载代码

猜你喜欢

转载自blog.csdn.net/weixin_44751294/article/details/111572558