Подключение DS18B20 к ATmega8 и вывод на LCD HD44780-MicroPi

#define DEVICES_ERROR  1

#include “config.h”

#include <avr/io.h>

#include <avr/interrupt.h>

#include <util/delay.h>

#include “OneWire.h”

 

uint8_t ONE_WIRE_DQ = PINB0;

 

void oneWireInit(uint8_t pin) {

  ONE_WIRE_DQ = pin;

  ONE_WIRE_PORT |= (1 << ONE_WIRE_DQ);

  ONE_WIRE_DDR |= (1 << ONE_WIRE_DQ); // выход

}

 

/*

* сброс

*/

uint8_t reset() {

  uint8_t response;

 

  // импульс сброса, минимум 480us

  ONE_WIRE_PORT &= ~(1 << ONE_WIRE_DQ);

  ONE_WIRE_DDR |= (1 << ONE_WIRE_DQ); // выход

  _delay_us(480);

 

  // Когда ONE WIRE устройство обнаруживает положительный перепад, он ждет от 15us до 60us

  ONE_WIRE_DDR &= ~(1 << ONE_WIRE_DQ); // вход

  _delay_us(60);

 

  // и затем передает импульс присутствия, перемещая шину в логический «0» на длительность от 60us до 240us.

  response = (ONE_WIRE_PIN & (1 << ONE_WIRE_DQ));

  _delay_us(410);

 

  // если 0, значит есть ответ от датчика, если 1 – нет

  return response;

}

 

/*

* отправить один бит

*/

void writeBit(uint8_t bit) {

  if (bit & 1) {

    cli();

    // логический «0» на 1us

    ONE_WIRE_PORT &= ~(1 << ONE_WIRE_DQ);

    ONE_WIRE_DDR |= (1 << ONE_WIRE_DQ); // выход

    _delay_us(10);

    sei();

    ONE_WIRE_DDR &= ~(1 << ONE_WIRE_DQ); // вход

    _delay_us(55);

  } else {

    cli();

    // логический «0» на 1us

    ONE_WIRE_PORT &= ~(1 << ONE_WIRE_DQ);

    ONE_WIRE_DDR |= (1 << ONE_WIRE_DQ); // выход

    _delay_us(65);

    ONE_WIRE_DDR &= ~(1 << ONE_WIRE_DQ); // вход

    sei();

    _delay_us(5);

  }

}

 

/*

* отправить один байт

*/

void writeByte(uint8_t byte) {

  uint8_t i = 8;

  while (i–) {

    writeBit(byte & 1);

    byte >>= 1;

  }

}

 

/*

* получить один байт

*/

uint8_t readByte() {

  uint8_t i = 8, byte = 0;

  while (i–) {

    byte >>= 1;

    byte |= (readBit() << 7);

  }

  return byte;

}

 

/*

* получить один бит

*/

uint8_t readBit(void) {

  uint8_t bit = 0;

  cli();

  // логический «0» на 1us

  ONE_WIRE_PORT &= ~(1 << ONE_WIRE_DQ);

  ONE_WIRE_DDR |= (1 << ONE_WIRE_DQ); // вход

  _delay_us(3);

 

  // освободить линию и ждать 14us

  ONE_WIRE_DDR &= ~(1 << ONE_WIRE_DQ); // вход

  _delay_us(10);

 

  // прочитать значение

  if (ONE_WIRE_PIN & (1 << ONE_WIRE_DQ)) {

    bit = 1;

  }

 

  // ждать 45us и вернуть значение

  sei();

  _delay_us(45);

  return bit;

}

 

/*

* читать ROM подчиненного устройства (код 64 бита)

*/

uint64_t 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 setDevice(uint64_t rom) {

  uint8_t i = 64;

  reset();

  writeByte(CMD_MATCHROM);

  while (i–) {

    writeBit(rom & 1);

    rom >>= 1;

  }

}

 

/*

* провеска CRC, возвращает “0”, если нет ошибок

* и не “0”, если есть ошибки

*/

uint8_t 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;

}

 

/*

* поиск устройств

*/

void searchRom(uint64_t * roms, uint8_t & n) {

  uint64_t lastAddress = 0;

  uint8_t lastDiscrepancy = 0;

  uint8_t err = 0;

  uint8_t i = 0;

  do {

    do {

      lastAddress = searchNextAddress(lastAddress, lastDiscrepancy);

      if(lastAddress != DEVICES_ERROR) {

        uint8_t crc = crcCheck(lastAddress, 8);

        if (crc == 0) {

          roms[i++] = lastAddress;

          err = 0;

        } else {

          err++;

        }

      } else {

        err++;

      }

      if (err > 3) {

        return;

      }

    } while (err != 0);

  } while (lastDiscrepancy != 0 && i < n);

  n = i;

}

 

/*

* поиск следующего подключенного устройства

*/

uint64_t searchNextAddress(uint64_t lastAddress, uint8_t & lastDiscrepancy) {

  uint8_t searchDirection = 0;

  uint64_t newAddress = 0;

  uint8_t idBitNumber = 1;

  uint8_t lastZero = 0;

  reset();

  writeByte(CMD_SEARCHROM);

 

  while (idBitNumber < 65) {

    uint8_t idBit = readBit();

    uint8_t cmpIdBit = readBit();

 

    // id_bit = cmp_id_bit = 1

    if (idBit == 1 && cmpIdBit == 1) {

      return DEVICES_ERROR;

    } 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 skipRom() {

  reset();

  writeByte(CMD_SKIPROM);

}

micro-pi.ru

Подключение DS18B20 к ATtiny2313 и вывод на HD44780-MicroPi

#define F_CPU 8000000UL

#include <avr/io.h>

#include <util/delay.h>

#include <avr/interrupt.h>

 

#include “ds18b20.h”

 

/*

* ds18b20 – инициализация

*/

uint8_t resetDS18B20() {

  uint8_t i;

 

  // импульс сброса, минимум 480?s

  DS18B20_PORT &= ~(1 << DS18B20_DQ);

  DS18B20_DDR |= (1 << DS18B20_DQ); // выход

  _delay_us(480);

 

  // Когда DS18B20 обнаруживает положительный перепад, он ждет от 15?s до 60?s

  DS18B20_DDR &= ~(1 << DS18B20_DQ); // вход

  _delay_us(60);

 

  // и затем передает импульс присутствия, перемещая шину в логический «0» на длительность от 60?s до 240?s.

  i = (DS18B20_PIN & (1 << DS18B20_DQ));

  _delay_us(420);

 

  //return the read value, 0=ok, 1=error

  return i;

}

 

/*

* написать один бит

*/

inline void writeBitDS18B20(uint8_t bit) {

  // логический «0» на 1?s

  DS18B20_PORT &= ~(1 << DS18B20_DQ);

  DS18B20_DDR |= (1 << DS18B20_DQ); // выход

  _delay_us(1);

 

  // если нужно написать 1, нужно освободить линию (если не – держать низкий уровень)

  if (bit) {

    DS18B20_DDR &= ~(1 << DS18B20_DQ); // вход

  }

 

  // ждать 60?s и освободить линию

  _delay_us(60);

  DS18B20_DDR &= ~(1 << DS18B20_DQ); // вход

}

 

/*

* прочитать один бит

*/

uint8_t readBitDS18B20(void) {

  uint8_t bit = 0;

 

  // логический «0» на 1?s

  DS18B20_PORT &= ~(1 << DS18B20_DQ);

  DS18B20_DDR |= (1 << DS18B20_DQ); // вход

  _delay_us(1);

 

  // освободить линию и ждать 14?s

  DS18B20_DDR &= ~(1 << DS18B20_DQ); // вход

  _delay_us(14);

 

  // прочитать значение

  if (DS18B20_PIN & (1 << DS18B20_DQ)) {

    bit = 1;

  }

 

  // ждать 45?s и вернуть значение

  _delay_us(45);

  return bit;

}

 

/*

* написать один байт

*/

void writeByteDS18B20(uint8_t byte) {

  uint8_t i = 8;

  while (i–) {

    writeBitDS18B20(byte & 1);

    byte >>= 1;

  }

}

 

/*

* прочитать один байт

*/

uint8_t readByteDS18B20(void) {

  uint8_t i = 8, n = 0;

  while (i–) {

    n >>= 1;

    n |= (readBitDS18B20() << 7);

  }

  return n;

}

 

/*

* получить температуру

*/

double getTempDS18B20() {

  uint8_t temperatureL;

  uint8_t temperatureH;

  double retd = 0;

 

  if (DS18B20_STOPINTERRUPTONREAD == 1) {

    cli();

  }

 

  resetDS18B20(); // сброс

  writeByteDS18B20(DS18B20_CMD_SKIPROM); // пропуск ПЗУ(ROM)

  writeByteDS18B20(DS18B20_CMD_CONVERTTEMP); // начать преобразование показаний температуры

 

  while (!readBitDS18B20()); // ждать, пока преобразование не завершится

 

  resetDS18B20(); // сброс

  writeByteDS18B20(DS18B20_CMD_SKIPROM); // пропуск ПЗУ(ROM)

  writeByteDS18B20(DS18B20_CMD_RSCRATCHPAD); // читать scratchpad

 

  // прочитать 2 байта из scratchpad

  temperatureL = readByteDS18B20();

  temperatureH = readByteDS18B20();

 

  if (DS18B20_STOPINTERRUPTONREAD == 1) {

    sei();

  }

 

  // преобразовать полученное 12 битное значение

  retd = ((temperatureH << 8) + temperatureL) * 0.0625;

 

  return retd;

}

micro-pi.ru

1-Wire. Работа с DS18B20. Часть 1

     Все (и в том числе я) называют DS18B20 цифровым датчиком температуры. Однако это не просто датчик, это программируемый цифровой термометр. Он измеряет температуру в диапазоне от –55 до +125 градусов Цельсия, имеет программируемое температурное разрешение от 9 до 12 бит и позволяет задавать верхний и нижний температурные пороги, в случае превышения которых,  устанавливается флаг аварии. 

   Каждый термометр DS18B20 имеет уникальный 64 битный серийный номер, который используется для его адресации на 1-Wire шине. Это позволяет объединять на одной шине несколько независимо работающих термометров и осуществлять между ними и микроконтроллером обмен данными по 1-Wire протоколу. 

   Также особенностью данного термометра является то, что его можно запитывать не только от источника питания, но и от сигнального провода. Это так называемый режим паразитного питания. В этом режиме для подключения DS18B20 требуется всего два провода — сигнальный и возвратный (земляной, GND).

       Схема подключения нескольких датчиков DS18B20 с внешним питанием.     1-Wire шина  должна быть обязательно подтянута к плюсу питания через резистор номиналом 4,7 Ком. Напряжение источника питания от 3 до 5 Вольт. 

   Схема подключения датчика DS18B20 в режиме паразитного питания. 

   Вывод Vdd соединяется с GND, а 1-Wire шина дополнительно подключается к источнику питания через полевой транзистор. 

   Когда датчик DS18B20 выполняет преобразование температуры или копирует данные из ОЗУ в EEPROM память, он потребляет ток до 1,5 мА. Этот ток может вызывать недопустимое снижение напряжения на 1-Wire шине. Чтобы этого не происходило, 1-Wire шину на время выполнения этих операций подключают к источнику питания. Для этого и нужен полевой транзистор.   

     Для обмена данными термометр DS18B20 использует 1-Wire протокол (однопроводный протокол). Это низкоскоростной двунаправленный полудуплексный последовательный протокол обмена данными использующий всего один сигнальный провод. Естественно требуется еще и возвратный (земляной) провод, но об этом маркетологи обычно умалчивают. 1-Wire протокол был разработан фирмой Dallas Semiconductor в конце 90-х годов.    

     

   Имеется несколько типов сигналов, определенных 1-Wire протоколом – импульс сброса, импульс присутствия, запись 0, запись 1, чтение 0 и чтение 1. Все эти сигналы, за исключением импульса присутствия, формируются на шине главным устройством — MASTERом . В нашем случае это  микроконтроллер AVR. 

  Принцип формирования сигналов во всех случаях одинаковый. В начальном состоянии 1-Wire шина с помощью резистора подтянута к плюсу питания. Главное устройство «проваливает» на определенное время 1-Wire шину в ноль, затем «отпускает» ее и, если нужно, «слушает» ответ подчиненного (SLAVE) устройства. В нашем случае подчиненное устройство – термометр DS18B20. 

 

  Физически это реализуется так. 

  Операция записи бита: Вывод микроконтроллера устанавливается в режим выхода и на нем устанавливается логический ноль. Выдерживается пауза, длительность которой зависит от значения передаваемого бита (0 или 1), затем вывод переводится в режим входа в состоянии Hi-z и снова выдерживается пауза. 

  Операция чтения бита: Вывод микроконтроллера устанавливается в режим выхода и на нем устанавливается логический ноль. Выдерживается определенная пауза, вывод переводится в режим входа в состоянии Hi-z, выдерживается пауза, а затем микроконтроллер считывает потенциал вывода. 

 

   Все сеансы связи микроконтроллера с датчиком DS18B20 начинаются с сигнала сброса.  Микроконтроллер на 480 мкс «проваливает» 1-Wire шину в ноль, а затем «отпускает» ее. Если к шине подключен термометр DS18B20, то он  обнаруживает положительный перепад и после паузы в 15-60 мкс отвечает микроконтроллеру импульсом присутствия — «проваливает» шину в ноль на время от 60 до 240 мкс. 

  

   Обмен данными по 1-Wire шине происходит последовательно, младшим битом вперед. Передача или прием одного бита данных выполняются в течении фиксированного промежутка времени, так называемого тайм слота (time slot). Различают тайм слоты записи и тайм слоты чтения. Длительность всех тайм слотов должна быть > 60 мкс, а пауза между тайм слотами  > 1 мкс.   

 

   Для передачи нуля микроконтроллер «проваливает» 1-Wire шину на время от 60 до 120 мкс. Затем «отпускает» ее и перед записью следующего бита выдерживает паузу >1  мкс.

   Для передачи единицы микроконтроллер «проваливает» 1-Wire шину на время от 1 до 15 мкс,  «отпускает» ее и выдерживает паузу. Пауза должна быть такой, чтобы длительность тайм слота была > 60+1 мкс. 

   

   DS18B20 является подчиненным устройством и может передавать данные, только когда микроконтроллер формирует на 1-Wire шине тайм слоты чтения. Для формирования тайм слота чтения микроконтроллер «проваливает» 1-Wire шину на время от 1 до 15 мкс, а затем «отпускает» ее, передавая  управление состоянием 1-Wire шины датчику DS18B20. Если DS18B20 передает ноль, он удерживает шину в «проваленном» состоянии (в состоянии логического нуля) до конца тайм слота. Если он передает 1, он оставляет шину в «подтянутом» состоянии. 

   Микроконтроллер может считывать данные датчика DS18B20 через 15 мкс после начала тайм слота чтения. 

chipenable.ru

Подключение температурного датчика DS18B20 по схеме с «паразитным» питанием

Существует несколько способов подключения датчиков температуры DS18B20 к сети 1-wire. В этой заметке я опишу способ подключения температурного датчика по схеме с «паразитным» питанием,  где в качестве мастера сети 1-wire используется оригинальное USB-устройство DS9490R.

Данный способ подключения является очень удобным, т.к. используются всего две жилы проводника, а так же нет необходимости в дополнительной обвязке со схемой стабилизации питания (если вы планируете использовать в качестве мастера другие устройства, то возможно будет необходима подтяжка — об этом я расскажу позже). Правда стоит отметить, что в официальной документации говорится о возможных негативных последствиях при подключении температурного датчика, но на практике, при использовании мастера DS9490R,  я с этими проблемами не встречался.

Итак, схема подключения датчика довольно простая: в качестве шины сети 1-wire я использую простой кабель UTP-5 (витая пара) и, с целью уменьшения помех на линии, использовал для DATA и GND две свитых в одну пару жилы. Ножки датчика 1 (GND) и 3 (Vdd) соединяются накоротко и подключаются к PIN4 у DS9490R. Ножка 2 (DATA) подключается к PIN3 у DS9490R. Таким способом к одному мастеру можно подключить много датчиков (я проверял работоспособность на 15 одновременно подключенных датчиках).

Принципиальная схема подключения DS18B20 с паразитным питанием:

После подключения, датчики появляются в OWFS и показывают температуру 🙂

Преимущества данной схемы подключения:

  • Простой и довольно дешевый способ подключения большого количества датчиков температуры
  • Нет необходимости во внешнем питании
  • Нет необходимости в дополнительной «обвязке»

Недостатки:

  • Возможна нестабильная работа на шинах большой длинны и большим количеством ведомых устройств в сети
  • Желательно использовать фирменный мастер сети DS9490R
Запись опубликована автором Ilshat в рубрике Без рубрики с метками DS18B20, датчики, температура.

dom-v-provodah.ru

alexxlab

leave a Comment