DS18B20温度传感器 - arduino

DS18B20测量温度范围是-55℃至125℃,精度为0.5℃。采用单总线进行数据及命令传输,可在同一总线上连接多个DS18B20,并采用地址进行器件选择与数据传输
产品封装
DS18B20温度传感器 - arduino_第1张图片
时序图
DS18B20温度传感器 - arduino_第2张图片
典型应用电路

  1. 典型电路
    DS18B20温度传感器 - arduino_第3张图片
  2. 寄生供电方式
    DS18B20温度传感器 - arduino_第4张图片

支持命令集
DS18B20温度传感器 - arduino_第5张图片
复位时序
DS18B20温度传感器 - arduino_第6张图片
读写时序
DS18B20温度传感器 - arduino_第7张图片


arduino 程序

#ifndef DS18B20_h
#define DS18B20_h

#include 

#if ARDUINO >= 100
#include "Arduino.h"       // for delayMicroseconds, digitalPinToBitMask, etc
#else
#include "WProgram.h"      // for delayMicroseconds
#include "pins_arduino.h"  // for digitalPinToBitMask, etc
#endif

// You can exclude certain features from DS18B20.  In theory, this
// might save some space.  In practice, the compiler automatically
// removes unused code (technically, the linker, using -fdata-sections
// and -ffunction-sections when compiling, and Wl,--gc-sections
// when linking), so most of these will not result in any code size
// reduction.  Well, unless you try to use the missing features
// and redesign your program to not need them!  DS18B20_CRC8_TABLE
// is the exception, because it selects a fast but large algorithm
// or a small but slow algorithm.



// You can exclude CRC checks altogether by defining this to 0
#ifndef DS18B20_CRC
#define DS18B20_CRC 1
#endif

// Select the table-lookup method of computing the 8-bit CRC
// by setting this to 1.  The lookup table enlarges code size by
// about 250 bytes.  It does NOT consume RAM (but did in very
// old versions of DS18B20).  If you disable this, a slower
// but very compact algorithm is used.
#ifndef DS18B20_CRC8_TABLE
#define DS18B20_CRC8_TABLE 1
#endif


#define FALSE 0
#define TRUE  1



class DS18B20
{
  private:
    uint8_t PIN;
    byte bitmask;

    // global search state
    byte ROM_NO[8];//search到的最新地址暂存

    uint8_t LastDiscrepancy;
    uint8_t LastDeviceFlag;
    byte search_new();
    byte senser_number; 

    void write(uint8_t v);    
    void write_bytes(const uint8_t *buf, uint16_t count);
    // Read a byte.
    uint8_t read(void);
    void read_bytes(uint8_t *buf, uint16_t count);
    // Write a bit. The bus is always left powered at the end, see
    // note in write() about that.
    void write_bit(uint8_t v);
    // Read a bit.
    uint8_t read_bit(void);
    // Issue a 1-Wire rom select command, you do the reset first.
    void select(const uint8_t rom[8]);
    // Perform a 1-Wire reset cycle. Returns 1 if a device responds
    // with a presence pulse.  Returns 0 if there is no device or the
    // bus is shorted or otherwise held low for more than 250uS
    uint8_t reset(void);
    // Clear the search state so that if will start from the beginning again.
    void reset_search();
    void search();    
  public:
    void set(byte n);
    byte getNumber();
    void search_again();//重新搜索      
    byte senser_addr[8][8];//地址储存,最多8个      
    DS18B20( uint8_t pin,byte sn);
    float get(byte n);
    void start(byte n);
    void start();
    boolean ready();
    // Look for the next device. Returns 1 if a new address has been
    // returned. A zero might mean that the bus is shorted, there are
    // no devices, or you have already retrieved all of them.  It
    // might be a good idea to check the CRC to make sure you didn't
    // get garbage.  The order is deterministic. You will always get
    // the same devices in the same order.


#if DS18B20_CRC
    // Compute a Dallas Semiconductor 8 bit CRC, these are used in the
    // ROM and scratchpad registers.
    static uint8_t crc8(const uint8_t *addr, uint8_t len);

#endif
};

#endif

实现文件

/*
Base on OneWire v2.2
Edit by savage 2014-05-07

*/

#include "DS18B20.h"

DS18B20::DS18B20(uint8_t pin,byte sn)
{
    PIN=pin;
    pinMode(pin, OUTPUT);
    digitalWrite(PIN,1);
    delayMicroseconds(1000);//初始化的时候,先要保证以高电平开始,顺便充电
    senser_number=0;
    byte li=10; 
    while(senser_number//查找传感器,直到数量超过设定值
    search_again(); 
    if(!li--)break;//最多10次
  }
  set(0x3F);//设定为10位模式(默认是12位模式)
}

void DS18B20::set(byte n){
    reset();    
    write(0xCC);//skip  
    write(0x4E);//write
    write(0);//Th
    write(0);//Tl
    write(n);//seting 10bit mode B00111111 10位模式
}   

// Returns 1 if a device asserted a presence pulse, 0 otherwise.
//
uint8_t DS18B20::reset()    
{   
    uint8_t r;
    pinMode(PIN,OUTPUT);// 把总线设置成输出
    digitalWrite(PIN,0); // 把总线拉低
    delayMicroseconds(480);//拉低电位至少480um,reset  
    pinMode(PIN,INPUT); // 把总线设置成输入

    noInterrupts(); 
    delayMicroseconds(70);      
    r=!digitalRead(PIN);//传感器回应
    interrupts();

    delayMicroseconds(410);
    return r;
}

//
// Write a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
void DS18B20::write_bit(uint8_t v)
{
  pinMode(PIN,OUTPUT);  // 总线设置输出
    if (v & 1) {        //写1
        noInterrupts(); 
    digitalWrite(PIN,0); // 先把总线拉低
        delayMicroseconds(5); // 延迟5us
        digitalWrite(PIN,1); // 写入数据
        interrupts();
        delayMicroseconds(55);
    } else {     //写0
        noInterrupts();
        digitalWrite(PIN,0);
        delayMicroseconds(60);      
    digitalWrite(PIN,1);
    interrupts();
        delayMicroseconds(5);
    }
}
//
// Read a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
//
uint8_t DS18B20::read_bit()
{
    uint8_t r;  
    pinMode(PIN,OUTPUT);
    noInterrupts();
    digitalWrite(PIN,0);//拉低电位1us以上
    delayMicroseconds(2);
    pinMode(PIN,INPUT);         
    delayMicroseconds(10);// let pin float, pull up will raise
    r = digitalRead(PIN);//必须在15us内采样
    interrupts();
    delayMicroseconds(50);
    return r;
}
//写
void DS18B20::write(uint8_t v) {
      noInterrupts();   
    uint8_t bitMask;
    for (bitMask = 0x01; bitMask; bitMask <<= 1) {
      DS18B20::write_bit( (bitMask & v)?1:0);
    }
    interrupts();
 }

void DS18B20::write_bytes(const uint8_t *buf, uint16_t count) {
  for (uint16_t i = 0 ; i < count ; i++)
    write(buf[i]);
}

// Read 
uint8_t DS18B20::read() {
      noInterrupts();   
    uint8_t bitMask;
    uint8_t r = 0;
    for (bitMask = 0x01; bitMask; bitMask <<= 1) {
      if ( DS18B20::read_bit()) r |= bitMask;
    }
    interrupts();
    return r;
}

void DS18B20::read_bytes(uint8_t *buf, uint16_t count) {
  for (uint16_t i = 0 ; i < count ; i++)
    buf[i] = read();
}

//
// Do a ROM select
//
void DS18B20::select(const uint8_t rom[8])
{
    uint8_t i;
    write(0x55);           // Choose ROM
    for (i = 0; i < 8; i++) write(rom[i]);
}
// 开始温度转换
void DS18B20::start(byte n){
     reset();
   select(senser_addr[n]);
   write(0x44);
}

void DS18B20::start(){
     reset();
   write(0xCC);//skip
   write(0x44);
}

boolean DS18B20::ready(){
      return read()&0x01;
}

float DS18B20::get(byte n){
    if(n>=senser_number)return 210;//超过范围
    reset();    
    select(senser_addr[n]); 
    write(0xBE); // 写入要求读取温度的命令到DS18B20
    byte data[9];
    byte i;
    for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = read(); // 每次读取1个字节..总共读取9个字节
  }
  if(crc8(data, 8)!=data[8])return 250;//crc 错误
  int raw = (data[1] << 8) | data[0];   
  return raw*0.0625;        
}

// You need to use this function to start a search again from the beginning.
// You do not need to do it for the first search, though you could.
//
void DS18B20::reset_search()
{
  // reset the search state
  LastDiscrepancy = 0;
  LastDeviceFlag = FALSE;
  for(int i = 7; ; i--) {
    ROM_NO[i] = 0;
    if ( i == 0) break;
  }
}


//
// Perform a search. If this function returns a '1' then it has
// enumerated the next device and you may retrieve the ROM from the
// DS18B20::address variable. If there are no devices, no further
// devices, or something horrible happens in the middle of the
// enumeration then a 0 is returned.  If a new device is found then
// its address is copied to newAddr.  Use DS18B20::reset_search() to
// start over.
//
// --- Replaced by the one from the Dallas Semiconductor web site ---
//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return TRUE  : device found, ROM number in ROM_NO buffer
//        FALSE : device not found, end of search
//
byte DS18B20::getNumber(){
    return senser_number;
    }
void DS18B20::search_again(){
    reset_search();
    search();
}   
void DS18B20::search(){
    byte j=0;//最多8个地址
    byte i;
    senser_number=0;
    byte search_err_count=10;//出错后最多重复10次

    while(search_new()){        
         if(crc8(ROM_NO, 7) != ROM_NO[7]){//CRC验证错误
        reset_search();
        j=0;
        search_err_count--;
        if (!search_err_count)break;
      }  
            for(i=0;i<8;i++){
                senser_addr[j][i]=ROM_NO[i];
            }           
        senser_number++;    
        j++;    
        if(j ==8)break;         
    }
}
byte DS18B20::search_new()
{
     byte newAddr[8];
   uint8_t id_bit_number;
   uint8_t last_zero, rom_byte_number, search_result;
   uint8_t id_bit, cmp_id_bit;

   byte rom_byte_mask, search_direction;

   // initialize for search
   id_bit_number = 1;
   last_zero = 0;
   rom_byte_number = 0;
   rom_byte_mask = 1;
   search_result = 0;

   // if the last call was not the last one
   if (!LastDeviceFlag)
   {
      // 1-Wire reset
      if (!reset())
      {
         // reset the search
         LastDiscrepancy = 0;
         LastDeviceFlag = FALSE;
         return FALSE;
      }

      // issue the search command
      write(0xF0);

      // loop to do the search
      do
      {
         // read a bit and its complement
         id_bit = read_bit();
         cmp_id_bit = read_bit();

         // check for no devices on 1-wire
         //10->all 1; 01->all 0; 00->have 0 and 1;11->no device
         if ((id_bit == 1) && (cmp_id_bit == 1))
            break;
         else
         {
            // all devices coupled have 0 or 1
            if (id_bit != cmp_id_bit)
               search_direction = id_bit;  // bit write value for search
            else
            {
               // if this discrepancy if before the Last Discrepancy
               // on a previous next then pick the same as last time
               if (id_bit_number < LastDiscrepancy)
                  search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
               else
                  // if equal to last pick 1, if not then pick 0
                  search_direction = (id_bit_number == LastDiscrepancy);

               // if 0 was picked then record its position in LastZero
               if (search_direction == 0)
               {
                  last_zero = id_bit_number;
               }
            }

            // set or clear the bit in the ROM byte rom_byte_number
            // with mask rom_byte_mask
            if (search_direction == 1)
              ROM_NO[rom_byte_number] |= rom_byte_mask;
            else
              ROM_NO[rom_byte_number] &= ~rom_byte_mask;

            // serial number search direction write bit
            write_bit(search_direction);

            // increment the byte counter id_bit_number
            // and shift the mask rom_byte_mask
            id_bit_number++;
            rom_byte_mask <<= 1;

            // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
            //完成一个周期
            if (rom_byte_mask == 0)
            {
                rom_byte_number++;
                rom_byte_mask = 1;
            }
         }
      }
      while(rom_byte_number < 8);  // loop until through all ROM bytes 0-7

      // if the search was successful then
      if (!(id_bit_number < 65))
      {
         // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
         LastDiscrepancy = last_zero;

         // check for last device
         if (LastDiscrepancy == 0)
            LastDeviceFlag = TRUE;
         search_result = TRUE;
      }
   }
   // if no device found then reset counters so next 'search' will be like a first
   if (!search_result || !ROM_NO[0])
   {
      LastDiscrepancy = 0;
      LastDeviceFlag = FALSE;
      search_result = FALSE;
   }
   for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
   return search_result;
  }


#if DS18B20_CRC
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
// Compute a Dallas Semiconductor 8 bit CRC directly.
// this is much slower, but much smaller, than the lookup table.
//
uint8_t DS18B20::crc8(const uint8_t *addr, uint8_t len)
{
    uint8_t crc = 0;    
    while (len--) {
        uint8_t inbyte = *addr++;
        for (uint8_t i = 8; i; i--) {
            uint8_t mix = (crc ^ inbyte) & 0x01;
            crc >>= 1;
            if (mix) crc ^= 0x8C;
            inbyte >>= 1;
        }
    }
    return crc;
}
#endif

主程序代码

#include "DS18B20.h"

DS18B20  ds(9,1);//pin9,连接1个DS18B20

void setup() {
  SERIAL_BEGIN();
  byte i;
  byte j;
  for (j = 0; j < ds.getNumber(); j++) {
    for (i = 0; i < 8; i++) {
      PRINT(ds.senser_addr[j][i]);
      PRINT(",");
    }
    PRINT("CRC=");
    PRINT(ds.crc8(ds.senser_addr[j], 7) );
    PRINT("\n");
  }
  println(ds.getNumber(),10,serial_puts);

}

void loop() { 
  ds.start();//开始测量(所有传感器)
  _delay_ms(200);

  float a=ds.get(0);
  PRINT("temp = ");
  if (a>200)
    PRINT("CRC error\n");
  else
  {
    PRINT(a);
    PRINT("\n");
  }
}

int main()
{
  setup();
  while(1)
    loop();
}

你可能感兴趣的:(AVR,&,Arduino)