DS18B20温度检测

大城市里の小女人 提交于 2020-12-01 09:03:48

STM32F407VET6 -- FreeRTOS -- DS18B20温度检测

1、DS18B20 单线数字温度传感器,即“一线器件”,其具有独特的优点:

  a、采用单总线的接口方式 与微处理器连接时仅需要一根线即可实现微处理器与 DS18B20 的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量。
  b、测量温度范围宽,测量精度高 DS18B20 的测量范围为 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C范围内,精度为 ± 0.5°C 。
  c、在使用中不需要任何外围元件。
  d、支持多点组网功能,多个 DS18B20 可以并联在惟一的单线上,实现多点测温。
  e、供电方式灵活 DS18B20 可以通过内部寄生电路从数据线上获取电源。因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。
  f、测量参数可配置 DS18B20 的测量分辨率可通过程序设定 9~12 位。
  g、负压特性电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。
  h、掉电保护功能 DS18B20 内部含有 EEPROM ,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。

2、DS18B20内部结构:

  DS18B20内部主要包括,64位ROM、2字节温度输出寄存器、1字节上下警报寄存器(TH和TL)和1字节配置寄存器。ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同,这样就可以实现一根总线挂接多个DS18B20的目的。配置寄存器允许用户将温度 - 数字转换的分辨率设置为9,10,11或12位。DS18B20控制引脚需要一个上拉电阻,并通过开漏模式连接到总线。DS18B20无需外部电源也可运行,当总线为高电平时,通过DQ引脚提高电源,并将电存储在Cpp电容中,在总线处于低电平时为器件供电,这种方法称为“寄生电源”。另外DS18B20也可通过VDD供电。

3、DS18B20内部构成:

  

  高速暂存存储器由9个字节组成,分别为:

    1、温度的低八位数据

    2、温度的高8位数据

    3、高温阈值

    4、低温阈值

    5、配置寄存器

    6、保留

    7、保留

    8、保留

    9、CRC校验

  器件断电时,EEPROM寄存器中的数据保留,上电后,EEPROM数据被重新加载到相应的寄存器位置,也可以使用命令随时将数据从EEPROM重新加载到暂存器中。

4、温度寄存器数据格式:

  

  DS18B20中的温度传感器数据用16位二进制形式提供,其中S为符号位(正数S=0,负数S=1)。温度传感器的分辨率可由用户配置为9、10、11或12位,分别对应0.5℃、0.25 ℃、0.125℃和0.0625℃的增量。开机时的默认分辨率是12位。如果DS18B20配置为12位分辨率,那么温度寄存器中的所有位都将包含有效数据。对于11位分辨率,bit0没有定义。对于10位分辨率,bit1和bit0没有定义,对于9位分辨率,bit2、bit1和bit0没有定义。

5、TH和TL报警寄存器格式:

  

  TH和TL寄存器存储温度报警触发值,符号位S表示值是正还是负,对于正数,S=0,对于负数,S=1。DS18B20执行温度转换后,将温度值与用户定义的两个报警触发值进行比较,由于TH和TL是8位寄存器,因此在比较TH和TL时只使用温度寄存器的第11位到第4位,如果被测温度低于或等于TL值,或高于或等于TH值,则在DS18B20内部存在报警条件,并设置报警标志。主设备可以通过发出一个[EC]命令来检查总线上所有DS18B20的报警标志状态。TH和TL寄存器是非易失性的(EEPROM),当设备断电时,它们将保留数据。可以通过内存部分暂存器的字节2和字节3访问TH和TL。

6、配置寄存器数据格式:

  

  在配置寄存器中,我们可以通过R0和R1设置DS18B20的转换分辨率,DS18B20在上电后默认R0=1和R1=1(12分辨率),寄存器中的第7位和第0位到4位保留给设备内部使用。

7、 初始化时序:

  

  主机首先拉低总线,并至少持续480微秒;然后拉高释放总线,并在随后的480微秒时间内对总线进行检测;如果有低电平出现说明总线上有器件已做出应答,若一直都是高电平说明总线上无器件应答。做为从器件的DS18B20在一上电后就一直在检测总线上是否有至少480微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。
8、写操作时序:
  
  写周期最少为60微秒,最长不超过120微秒。若主机想写0,则把总线拉低电平最少60微秒直至写周期结束。若主机想写1,则一开始主机先把总线拉低1微秒表示写周期开始,1微秒后就释放总线为高电平,一直到写周期结束。做为从机的DS18B20则在检测到总线被拉底后等待15微秒然后从15us到45us开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。

9、读操作时序:
  
  对于读数据操作时序也分为读0时序和读1时序两个过程。读时序是从主机把单总线拉低之后,在1微秒之后就得释放单总线为高电平,以让DS18B20把数据传输到单总线上。DS18B20在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束。若要送出1则释放总线为高电平。主机在一开始拉低总线1微秒后释放总线,然后在包括前面的拉低总线电平1微秒在内的15微秒时间内完成对总线进行采样检测,采样期内总线为低电平则确认为0。采样期内总线为高电平则确认为1。完成一个读时序过程,至少需要60us才能完成。
 
 
10、STM32F407VET6 -- FreeRTOS -- 读写DS18B20温度传感器例程
#include "sys.h"
#include "FreeRTOS.h"
#include "task.h"
#include "ds18b20.h"
 
#define DQ_PORT  GPIOA
#define DQ_PIN  GPIO_Pin_0
#define DQ_RCC  RCC_AHB1Periph_GPIOA
#define DQ_OUT(s) (s == 0)? GPIO_ResetBits(DQ_PORT, DQ_PIN) : GPIO_SetBits(DQ_PORT, DQ_PIN)
// 读取 DQ 输入电平
#define DQ_READ() (GPIO_ReadInputDataBit(DQ_PORT, DQ_PIN) == Bit_SET)

#define DS18B20_PRIO  2 // 任务优先级
#define DS18B20_STK_SIZE 128 // 任务堆栈大小

// 温度值,精度:0.01℃,最高位为符号位(1为负0为正)
// 注:当传感器不正常时温度值为0xFFFF
static unsigned short int TemperatureValue = 0;
 
// 引脚初始化
static void ds18b20_gpio_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(DQ_RCC, ENABLE); // 使能GPIO时钟
  GPIO_InitStructure.GPIO_Pin = DQ_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 普通输出
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; // 设为开漏输出
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上下拉电阻不使能
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // IO口最大速度
  GPIO_Init(DQ_PORT, &GPIO_InitStructure); // 初始化
  DQ_OUT(1); // 总线初始化状态为高电平
}
 
// 基于 168MHz 主频的粗略延时
static void ds18b20_delay(unsigned int us)
{
  unsigned int i;
  unsigned char k = 0;
 
  for(i = 0; i < us; i++)
  {
    for(k = 0; k < 10; k++)
    {
     }
  }
}

// DS18B20复位
// 返回值:0=复位成功,1=复位失败
static unsigned char ds18b20_reset(void)
{
  unsigned char flag = 0;
  unsigned int timeout = 0;
 
  DQ_OUT(0); // 拉低总线
  ds18b20_delay(520); // 持续最少480us
  DQ_OUT(1); // 释放总线
  ds18b20_delay(10); // 需要等待15 - 60us
  // 进入接收模式,此时传感器会拉低总线,持续时间:60 - 240us
  while(DQ_READ())
  {
    if(++timeout > 200)
    {
      flag = 1;
      break;
    }
    ds18b20_delay(5); // 等待5us
  }
 
  // 等待总线被释放  
  timeout = 0;
  while(!DQ_READ())
  {
    if(++timeout > 2000)
    {
      flag = 1;
      break;
    }
    ds18b20_delay(10); // 等待10us
  }
  return flag;
}

// 向DS18B20写一个字节
static void ds18b20_write_byte(unsigned char dat)
{
  unsigned char i = 0;
 
  for(i = 0; i < 8; i++)
  {
    DQ_OUT(0);
    ds18b20_delay(2); // 总线拉低持续时间要大于1us
    if(dat & (0x1 << i)) // 低位先发
    {
      DQ_OUT(1);
    }
    else
    {
      DQ_OUT(0);
    }
    ds18b20_delay(60); // 延时60us,等待ds18b20采样读取
    DQ_OUT(1); // 释放总线
    ds18b20_delay(2);
  }
}

// 从DS18B20读取一个字节
// 返回值:读到的数据
static unsigned char ds18b20_read_byte(void)
{
  unsigned char i = 0;
  unsigned char dat = 0;
  for(i = 0; i < 8; i++)
  {
    DQ_OUT(0); // 拉低总线
    ds18b20_delay(2);
    DQ_OUT(1); // 释放总线
    ds18b20_delay(2);
    if(DQ_READ()) // 读时隙产生7 us后读取总线数据
    {
      dat |= 0x1 << i; // 低位先收
    }
    ds18b20_delay(60); // 延时60us,满足读时隙的时间长度要求
    DQ_OUT(1); // 释放总线
    ds18b20_delay(2);
  }
  return dat;
}

// 获取温度值线程
static void ds18b20_task(void *arg)
{
  unsigned char byte = 0;
  unsigned short int temp = 0;
  ds18b20_gpio_init();
  while(1)
  {
    // 开始采集温度数据
    if(ds18b20_reset() != 0)
    {
      continue;
    }
    taskENTER_CRITICAL(); // 进入临界区
    ds18b20_write_byte(0xCC); // skip rom
    ds18b20_write_byte(0x44); // 启动温度转换
    taskEXIT_CRITICAL(); // 退出临界区
    vTaskDelayMs(500);
    if(ds18b20_reset() != 0)
    {
      continue;
    }
    taskENTER_CRITICAL(); // 进入临界区
    ds18b20_write_byte(0xCC); // skip rom
    ds18b20_write_byte(0xBE); // 发出读取命令
    byte = ds18b20_read_byte(); // 读出温度低八位
    temp = ds18b20_read_byte(); // 读出温度高八位
    taskEXIT_CRITICAL(); // 退出临界区
    temp = temp << 8;
    temp = temp | byte;
    // 高五位为符号位,当温度为正的时候,高五位的字节是0,当温度为负的时候,高五位字节为1
    byte = 0x00; // 温度为正,正温度把16进制数转成10进制即可
    if(temp & 0xF800)
    {
      // 负温度把16进制数取反后加1再转成10进制数
      temp = (~temp) + 1;
      byte = 0x80; // 温度为负
    }
    temp = (temp * 25) >> 2; // DS18B20的分辨率是0.0625度,保留两位小数即:6.25 = 25 / 4;
    if(byte == 0x80)
    {
      temp |= 0x8000; // 加上符号标志
    }
    taskENTER_CRITICAL(); // 进入临界区
    TemperatureValue = temp;
    taskEXIT_CRITICAL(); // 退出临界区
  
    vTaskDelayMs(1500); // 1.5s采集一次温度数据
  }
}
 

// 获取温度值
// 返回值:温度(精度:0.01℃,最高为符号位1为负0为正)
// 注:当传感器不正常时温度值为0xFFFF
unsigned short int ds18b20_get_temp_value(void)
{
  return TemperatureValue;
}

 

// 初始化 DS18B20
// 返回值:0=succ;1=failed
unsigned char ds18b20_init(void)
{
  unsigned char flag = 0;
  taskENTER_CRITICAL(); // 进入临界区
  // 创建任务,参数:任务函数、任务名称、任务堆栈大小、任务函数形参、任务优先级、任务句柄
  if(xTaskCreate(ds18b20_task, "ds18b20", DS18B20_STK_SIZE, NULL, DS18B20_PRIO, NULL) != pdPASS)
  {
    flag = 1;
  }
  taskEXIT_CRITICAL(); // 退出临界区
  return flag;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!