Подключение датчика температуры DS18B20 к Orange Pi, Banana Pi, Raspberry Pi

DS18B20, пожалуй, один из самых из известных и доступных датчиков температуры. В основном для чтения данных с DS18B20 используется микроконтроллеры, к примеру: ATmega8, ATtiny2313, Arduino и др.. С появлением одноплатных мини-компьютеров стало интересно, как будет работать подключённый датчик температуры DS18B20 к Orange Pi, Banana Pi или Raspberry Pi — самые популярнуе мини-компьютеры.
Для работы с GPIO на Orange Pi и Banana Pi необходимо установить WiringOP и BPI-WiringPi соответственно, и IDE Code::Blocks.
При создании статьи был выбран Banana Pi M3, так как он  у меня постоянно включён. Но данный пример программы будет работать и при подключении DS18B20 к Orange Pi или Raspberry Pi.

OneWire библиотека

OneWire.h

#ifndef ONEWIRE_H
#define ONEWIRE_H

#define CMD_CONVERTTEMP    0x44
#define CMD_RSCRATCHPAD    0xbe
#define CMD_WSCRATCHPAD    0x4e
#define CMD_CPYSCRATCHPAD  0x48
#define CMD_RECEEPROM      0xb8
#define CMD_RPWRSUPPLY     0xb4
#define CMD_SEARCHROM      0xf0
#define CMD_READROM        0x33
#define CMD_MATCHROM       0x55
#define CMD_SKIPROM        0xcc
#define CMD_ALARMSEARCH    0xec

#include <stdint.h>

class OneWire {
private:
  int pin;
  uint64_t searchNextAddress(uint64_t, int&);

public:
  OneWire(int);
  virtual ~OneWire();

  int reset(void);
  int crcCheck(uint64_t, uint8_t);
  uint8_t crc8(uint8_t*, uint8_t);
  void oneWireInit();
  void writeBit(uint8_t);
  void writeByte(uint8_t);
  void setDevice(uint64_t);
  void searchRom(uint64_t*, int&);
  void skipRom(void);
  uint8_t readByte(void);
  uint8_t readBit(void);
  uint64_t readRoom(void);
};

#endif // ONEWIRE_H

OneWire.cpp

#include "OneWire.h"
#include <wiringPi.h>
#include <stdexcept>
#include <iostream>

OneWire::OneWire(int _pin) :
    pin(_pin) {
}

OneWire::~OneWire() {
}

void OneWire::oneWireInit() {
  if (wiringPiSetup() == -1) {
    throw std::logic_error("WiringPi Setup error");
  }
  pinMode(pin, INPUT);
}

/*
 * сброс
 */
int OneWire::reset() {
  int response;

  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW);
  delayMicroseconds(480);

  // Когда ONE WIRE устройство обнаруживает положительный перепад, он ждет от 15us до 60us
  pinMode(pin, INPUT);
  delayMicroseconds(60);

  // и затем передает импульс присутствия, перемещая шину в логический «0» на длительность от 60us до 240us.
  response = digitalRead(pin);
  delayMicroseconds(410);

  // если 0, значит есть ответ от датчика, если 1 - нет
  return response;
}

/*
 * отправить один бит
 */
void OneWire::writeBit(uint8_t bit) {
  if (bit & 1) {
    // логический «0» на 10us
    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);
    delayMicroseconds(10);
    pinMode(pin, INPUT);
    delayMicroseconds(55);
  } else {
    // логический «0» на 65us
    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);
    delayMicroseconds(65);
    pinMode(pin, INPUT);
    delayMicroseconds(5);
  }
}

/*
 * отправить один байт
 */
void OneWire::writeByte(uint8_t byte) {
  uint8_t i = 8;
  while (i--) {
    writeBit(byte & 1);
    byte >>= 1;
  }
}

/*
 * получить один байт
 */
uint8_t OneWire::readByte() {
  uint8_t i = 8, byte = 0;
  while (i--) {
    byte >>= 1;
    byte |= (readBit() << 7);
  }
  return byte;
}

/*
 * получить один бит
 */
uint8_t OneWire::readBit(void) {
  uint8_t bit = 0;
  // логический «0» на 3us
  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW);
  delayMicroseconds(3);

  // освободить линию и ждать 10us
  pinMode(pin, INPUT);
  delayMicroseconds(10);

  // прочитать значение
  bit = digitalRead(pin);

  // ждать 45us и вернуть значение
  delayMicroseconds(45);
  return bit;
}

/*
 * читать ROM подчиненного устройства (код 64 бита)
 */
uint64_t OneWire::readRoom(void) {
  uint64_t oneWireDevice;
  if (reset() == 0) {
    writeByte (CMD_READROM);
    //  код семейства
    oneWireDevice = readByte();
    // серийный номер
    oneWireDevice |= (uint16_t) readByte() << 8 | (uint32_t) readByte() << 16 | (uint32_t) readByte() << 24 | (uint64_t) readByte() << 32 | (uint64_t) readByte() << 40
        | (uint64_t) readByte() << 48;
    // CRC
    oneWireDevice |= (uint64_t) readByte() << 56;
  } else {
    return 1;
  }
  return oneWireDevice;
}

/*
 * Команда соответствия ROM, сопровождаемая последовательностью
 * кода ROM на 64 бита позволяет устройству управления шиной
 * обращаться к определенному подчиненному устройству на шине.
 */
void OneWire::setDevice(uint64_t rom) {
  uint8_t i = 64;
  reset();
  writeByte (CMD_MATCHROM);
  while (i--) {
    writeBit(rom & 1);
    rom >>= 1;
  }
}

/*
 * провеска CRC, возвращает "0", если нет ошибок
 * и не "0", если есть ошибки
 */
int OneWire::crcCheck(uint64_t data8x8bit, uint8_t len) {
  uint8_t dat, crc = 0, fb, stByte = 0;
  do {
    dat = (uint8_t)(data8x8bit >> (stByte * 8));
    // счетчик битов в байте
    for (int i = 0; i < 8; i++) {
      fb = crc ^ dat;
      fb &= 1;
      crc >>= 1;
      dat >>= 1;
      if (fb == 1) {
        crc ^= 0x8c; // полином
      }
    }
    stByte++;
  } while (stByte < len);   // счетчик байтов в массиве
  return crc;
}

uint8_t OneWire::crc8(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;
}

/*
 * поиск устройств
 */
void OneWire::searchRom(uint64_t * roms, int & n) {
  uint64_t lastAddress = 0;
  int lastDiscrepancy = 0;
  int err = 0;
  int i = 0;
  do {
    do {
      try {
        lastAddress = searchNextAddress(lastAddress, lastDiscrepancy);
        int crc = crcCheck(lastAddress, 8);
        if (crc == 0) {
          roms[i++] = lastAddress;
          err = 0;
        } else {
          err++;
        }
      } catch (std::exception & e) {
        std::cout << e.what() << std::endl;
        err++;
        if (err > 3) {
          throw e;
        }
      }
    } while (err != 0);
  } while (lastDiscrepancy != 0 && i < n);
  n = i;
}

/*
 * поиск следующего подключенного устройства
 */
uint64_t OneWire::searchNextAddress(uint64_t lastAddress, int & lastDiscrepancy) {
  uint64_t newAddress = 0;
  int searchDirection = 0;
  int idBitNumber = 1;
  int lastZero = 0;
  reset();
  writeByte (CMD_SEARCHROM);

  while (idBitNumber < 65) {
    int idBit = readBit();
    int cmpIdBit = readBit();

    // id_bit = cmp_id_bit = 1
    if (idBit == 1 && cmpIdBit == 1) {
      throw std::logic_error("error: id_bit = cmp_id_bit = 1");
    } else if (idBit == 0 && cmpIdBit == 0) {
      // id_bit = cmp_id_bit = 0
      if (idBitNumber == lastDiscrepancy) {
        searchDirection = 1;
      } else if (idBitNumber > lastDiscrepancy) {
        searchDirection = 0;
      } else {
        if ((uint8_t)(lastAddress >> (idBitNumber - 1)) & 1) {
          searchDirection = 1;
        } else {
          searchDirection = 0;
        }
      }
      if (searchDirection == 0) {
        lastZero = idBitNumber;
      }
    } else {
      // id_bit != cmp_id_bit
      searchDirection = idBit;
    }
    newAddress |= ((uint64_t) searchDirection) << (idBitNumber - 1);
    writeBit(searchDirection);
    idBitNumber++;
  }
  lastDiscrepancy = lastZero;
  return newAddress;
}

/*
 * пропустить ROM
 */
void OneWire::skipRom() {
  reset();
  writeByte (CMD_SKIPROM);
}

Подключение нескольких DS18B20 к Orange Pi на одну шину

Подключение датчика температуры DS18B20 к Orange Pi, Banana Pi, Raspberry Pi

При подключение нескольких датчиков DS18B20 к Orange Pi, Banana Pi или Raspberry Pi на одну шину, главное устройство (компьютер) должно определить коды ROM всех подчиненных устройств на шине. Команда SEARCH ROM [F0h] — (ПОИСК ROM) позволяет устройству управления определять номера и типы подчиненных устройств. Устройство управления изучает коды ROM через процесс устранения, которое требует, чтобы Главное устройство исполнил цикл Поиска ROM (то есть, команда ROM Поиска, сопровождаемая обменом данных). Эту процедуру необходимо выполнить столько раз, сколько необходимо, чтобы идентифицировать все из подчиненных устройств. Если есть только одно подчиненное устройство на шине, более простая команда READ ROM [33h] (Чтения ROM) может использоваться место процесса Поиска ROM.
После каждого цикла Поиска ROM, устройство управления шиной должно возвратиться к Шагу 1 (Инициализация) в операционной последовательности.

main.cpp

#include <iostream>
#include <wiringPi.h>
#include "OneWire.h"

using namespace std;

double getTemp(OneWire * oneWire, uint64_t ds18b20s) {
  uint8_t data[9];

  do {
    oneWire->setDevice(ds18b20s);
    oneWire->writeByte(CMD_CONVERTTEMP);

    delay(750);

    oneWire->setDevice(ds18b20s);
    oneWire->writeByte(CMD_RSCRATCHPAD);

    for (int i = 0; i < 9; i++) {
      data[i] = oneWire->readByte();
    }
  } while (oneWire->crc8(data, 8) != data[8]);

  return ((data[1] << 8) + data[0]) * 0.0625;
}

int main() {
  OneWire * ds18b20 = new OneWire(24);
  try {
    ds18b20->oneWireInit();

    double temperature;
    int n = 100;
    uint64_t roms[n];
    ds18b20->searchRom(roms, n);
    cout << "---------------------------------" << endl;
    cout << "devices = " << n << endl;
    cout << "---------------------------------" << endl;
    for (int i = 0; i < n; i++) {
      cout << "addr T[" << (i + 1) << "] = " << roms[i] << endl;
    }
    cout << "---------------------------------" << endl;
    while (1) {
      for (int i = 0; i < n; i++) {
        temperature = getTemp(ds18b20, roms[i]);
        cout << "T[" << (i + 1) << "] = " << temperature << "°C" << endl;
      }
      cout << "---------------------------------" << endl;
      delay(500);
    }
  } catch (exception & e) {
    cout << e.what() << endl;
  }

}
// site: http://micro-pi.ru

double getTemp(OneWire * oneWire, uint64_t ds18b20s) — возвращает данные температуры в градусах Цельсия.

Результат

Подключение датчика температуры DS18B20 к Orange Pi, Banana Pi, Raspberry Pi

Скачать проект Code::blocks

DS18B20 Banana Pi M3.zip

Если есть вопросы, пишите в комментариях, попробуем разобраться.

 

Похожие записи

Комментарии 44

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *