วันอังคารที่ 15 กันยายน พ.ศ. 2558

DS18B20 (Temperature Sensor)

การวัดอุณหภูมิด้วยไอซี DS18B20 Digital Thermometer

      ไอซีวัดอุณหภูมิในตระกูล DS18xx มีอยู่หลายรุ่น เช่น DS1820DS18S20 และ DS18B20 
เป็นไอซีที่วัดอุณหภูมิและให้ค่าแบบดิจิทัล เชื่อมต่อในรูปแบบของบัสที่เรียกว่า 1-Wire 
ไอซีเหล่านี้มีความแตกต่างกันเล็กน้อย แต่ในบทความนี้จะกล่าวถึงเฉพาะ DS18B20
        ในปัจจุบัน มีไอซีสำหรับวัดอุณหภูมิให้เลือกใช้อยู่หลายแบบ แบ่งตามรูปแบบของเอาต์พุตได้          
เป็นสองประเภทคือ ไอซีที่ให้เอาต์พุตแบบแอนะล็อก และแบบดิจิทัล โดยทั่วไปไอซีแบบดิจิทัล       
จะมีวงจรประเภท ADC (Analog to Digital Converter) รวมอยู่ภายใน บางตระกูลหรือบางรุ่น         
สามารถโปรแกรมหรืออ่านค่ารีจิสเตอร์ภายในได้ เช่น เพื่อกำหนดค่าที่เกี่ยวข้องกับการทำงาน             
ของไอซี ในส่วนการเชื่อมต่อกับไมโครคอนโทรลเลอร์ มักจะเป็นการสื่อสารข้อมูลแบบ SPI หรือ I2C 
เพื่อประหยัดขา I/O ในการเชื่อมต่อ   
       บทความนี้กล่าวถึง การใช้งานไอซี DS18B20 Digital Thermometer ของบริษัท Maxim 
และเขียนโปรแกรมติดต่อสื่อสารด้วย Arduino จุดเด่นของไอซีในตระกูลนี้คือ การสื่อสารข้อมูลด้วย
สัญญาณเพียงเส้นเดียว นำอุปกรณ์หรือไอซีมาต่อกันหลายตัวเป็นบัส (Bus) ได้โดยใช้โปรโตคอลสื่อสาร
ที่เรียกว่า 1-Wire (OneWire)

ข้อมูลเชิงเทคนิคเกี่ยวกับไอซี DS18B20:

  • ใช้แรงดันไฟเลี้ยง Vdd (หรือ Vcc) ได้ในช่วง 3.0V ถึง 5.5V
  • มี 3 ขา (สำหรับตัวถัง TO-92) คือ Gnd (Pin 1), DQ (Pin 2), Vdd (Pin 3)
  • ใช้งานได้สองแบบ: normal mode (ใช้ทั้ง 3 ขา) และ parasite power mode                                        
        (ใช้เพียง 2 ขา คือ DQ  และ GND ในขณะที่ขา Vdd จะต่อกับขา Gnd)
  • สามารถนำไอซีมาพ่วงต่อกันในบัสเดียว (เส้นสัญญาณ DQ) ได้หลายอุปกรณ์
  • ในการใช้งาน จะต้องต่อ pull-up 4.7kΩ (หรือน้อยกว่าได้เล็กน้อย) ที่ขา DQ กับแรงดันไฟเลี้ยง
  • วัดอุณหภูมิได้ในช่วง -55 °C ถึง +125 °C
  • มีความแม่นยำ ±0.5 °C สำหรับอุณหภูมิในช่วง -10°C ถึง +85°C
  • มีความละเอียดของค่าที่อ่านได้ 12 บิต (Resolution)
  • ใช้เวลาในการแปลงข้อมูลสำหรับ ADC ไม่เกิน 750 msec (มิลลิวินาที) สำหรับข้อมูล 12 บิต
  • ไอซีแต่ละตัวมีหมายเลขเฉพาะตัว ขนาด 64 บิต (64-bit serial code)
  • สำหรับตระกูล DS18B20 มีค่าไบต์สำหรับ 8-bit family code ตรงกับ 28h (0x28) 
        เป็นไบต์แรกของหมายเลขอุปกรณ์
ภายในไอซี DS18B20 มีหน่วยความจำแบบ SRAM ขนาดความจุ 9 ไบต์ (Byte 0 ถึง Byte 9) 
และเรียกว่า Scratchpadส่วนหนึ่งของหน่วยความจำนี้ จะใช้สำหรับเก็บค่าอุณหภูมิ
ที่ได้จากการอ่านและแปลงเป็นข้อมูลดิจิทัลในแต่ละครั้ง (ใช้ 2 ไบต์ และเก็บไว้ใน Byte 0 
และ Byte 1) และยังมีการคำนวณค่า CRC (checksum) ขนาดหนึ่งไบต์ด้วย (เก็บไว้ใน Byte 8)
รูปแสดงขาและตัวถัง TO-92 ของไอซี DS18B20




รูปแสดงอุปกรณ์สำหรับวัดอุณหภูมิ DS18B20 ที่ใช้ในการทดลอง
(Waterproof / encapsulated DS18B20 temperature sensor)
3-Wire connector: Black=GND, Yellow=DQ, Red=Vdd

Arduino Sketch

ในการเขียนโปรแกรมสำหรับ Arduino เพื่อเชื่อมต่อกับไอซี DS18B20 สามารถใช้ไลบรารี่ "OneWire.h" ของ Arduino ซึ่งทำให้สะดวกในการเขียนโปรแกรม เช่น เพื่อการค้นหาหลายเลข (64-bit code) ของอุปกรณ์ที่ต่ออยู่กับบัส 1-Wire การสั่งให้ไอซีตามหมายเลขอุปกรณ์อ่านและแปลงค่าอุณหภูมิ จากนั้นเว้นระยะเวลาอย่างน้อย 750msec แล้วจึงอ่านค่าจากหน่วยความจำ Scratchpad ของไอซี
โค้ดตัวอย่างต่อไปนี้ ทำหน้าที่ค้นหาไอซี DS18B20 ที่ต่ออยู่กับบัส 1-Wire ซึ่งในตัวอย่างนี้ ได้ใช้อุปกรณ์ 2 ชุด   ขา DQ ของไอซีแต่ละตัว จะนำไปต่อกับขา D2 ของ Arduino และที่ขานี้จะต้องต่อ 4.7kΩ แบบ pull-up กับ +5V อยู่ด้วย   ข้อมูลที่ได้จากอุปกรณ์วัดอุณหภูมิทั้งสองชุด จะปรากฏเป็นข้อความที่ถูกส่งผ่านทาง Serial (Baudrate 115200)

Sourcecode: ds18b20_demo.ino

///////////////////////////////////////////////////////////////////////////////
// Author: RSP @ Embedded System Lab (ESL), KMUTNB, Thailand
// Date: 2014-May-12
// Board: Arduino with ATmega168/328P (5V/16MHz)
// Arduino IDE: version 1.0.5
// Description:
//   This Arduino Sketch shows how to read temperature values from
//   two DS18B20 digital thermometers connected to the same bus (1-wire).
///////////////////////////////////////////////////////////////////////////////

#include <OneWire.h> // Use the Arduino "OneWire" library.

#define DS18S20_ID   (0x10)   // The byte code for the DS18S20 device family.
#define DS18B20_ID   (0x28)   // The byte code for the DS18B20 device family.

#define DQ_PIN       (2)      // Use Arduino D2 pin for I/O (connected to the DQ pin).
OneWire ds( DQ_PIN );         // Create a OneWire object.

#define NUM_DEVICES  (2)      // Specify the number of DS18B20 devices to be used.
byte ds_addr[NUM_DEVICES][8]; // used to stored 8-byte device addresses (for two devices)
char sbuf[20];                // used for sprintf()

// 'buf' must be an array of at least 8 bytes. 
boolean ds_addr_search( byte *buf ) { // Perform a DS18xx device search 
  if ( ds.search(buf) == 1 ) { // ok
    if ( OneWire::crc8( buf, 7 ) == buf[7] ) { // check the CRC byte
       return true; // CRC is valid
    }
  } else {
    ds.reset_search();
  }
  return false;
}

void ds_devices_scan() { // Scan devices on the 1-Wire bus
  for ( uint8_t dev=0; dev < NUM_DEVICES; dev++ ) { 
    uint8_t *addr = ds_addr[dev];
    memset( addr, 0x00, 8 );   
    if ( ds_addr_search( addr ) ) {
      for (uint8_t i=0; i < 8; i++) {
        sprintf( sbuf+3*i, "%02X ", addr[i] );
      }
      Serial.print( "Address found: " );
      Serial.print( sbuf );
      sprintf( sbuf, "(Device %d)", dev ); 
      Serial.println( sbuf );
      if ( addr[0] == DS18B20_ID ) {
        Serial.println( "This device is DS18B20." );
      }
      else if ( addr[0] == DS18S20_ID ) {
        Serial.println( "This device is DS18S20." );
      }
      else {
        Serial.println( "Unrecognized device family!" );
      }
    }
  }
}

void setup(void) {
  Serial.begin(115200);
  ds_devices_scan();
}
 
boolean ds_read_temp( byte *addr, int16_t *temp ) {
  static byte data[9];
  ds.reset();
  ds.select( addr );
  ds.write( 0x44, 1 );  // initiates a temperature conversion, enable pull-up on the 1-Wire bus
  delay( 800 );         // wait for at least 750ms for 12-bit ADC conversion time
  ds.reset();
  ds.select( addr );  
  ds.write( 0xBE );     // read Scratchpad
  for ( byte i=0; i < 9; i++ ) { // read 9 bytes in total
    data[i] = ds.read();
  }
  if ( OneWire::crc8( data, 8) == data[8] ) { // CRC is ok.
    int16_t t = data[1];
    t = (t << 8) + data[0];
    *temp = (t*10)/16;  // for DS18B20, use 0.0625 = 1/16 deg per bit
    return true;
  }
  return false;
}

void loop(void) {
  static int16_t temp;
  for ( uint8_t dev=0; dev < NUM_DEVICES; dev++ ) {
    if ( ds_addr[dev][0] != DS18B20_ID ) continue;
    if ( ds_read_temp( ds_addr[dev], &temp ) ) {
      char pm = (temp < 0) ? '-' : '+'; 
      temp = abs(temp);
      sprintf( sbuf, "Device %d: %c%d.%d C", dev, pm, (temp/10), (temp%10) );
      Serial.println( sbuf );
    } else {
      Serial.println( "Read operation failed!" );
    }
  }
}
/////////////////////////////////////////////////////////////////////////////////



รูปแสดงการวางแผนต่อวงจรบนเบรดบอร์ดด้วย Fritzing
วงจรนี้ใช้ไอซี DS18B20 จำนวน 2 ตัว และตัวต้านทาน 4.7kΩ 1 ตัว
การต่อไอซีแบบ 3-wire (normal power mode)



รูปแสดงการวางแผนต่อวงจรบนเบรดบอร์ดด้วย Fritzing
การต่อไอซีแบบ 2-wire (parasite power mode)



รูปแสดงฮาร์ดแวร์และการต่อวงจรทดลอง



รูปแสดงตัวอย่างข้อความใน Serial Monitor ที่ได้จากการทำงานของ Arduino ตามโค้ดตัวอย่าง
เริ่มต้นแสดงอุณหภูมิที่วัดได้จากอุปกรณ์ 2 ชุด วางอยู่ในตำแหน่งเดียวกัน และได้อุณหภูมิที่เท่ากัน



รูปแสดงข้อความในการวัดค่าอุณหภูมิจากอุปกรณ์ 2 ชุด แต่วัดอุณหภูมิในที่แตกต่างกัน
Device 1 นำไปไว้ใกล้แหล่งความร้อน (ช่องระบายความร้อนของคอมพิวเตอร์ Notebook)
ในขณะที่ Device 0 ยังวัดอุณหภูมิที่จุดเดิม


ที่มา : http://cpre.kmutnb.ac.th/esl/learning/index.php?article=ds18b20-temperature-sensor

ไม่มีความคิดเห็น:

แสดงความคิดเห็น