#include <OneWire.h> // Подключаем библиотеку для работы с термодатчиками DS18B20
OneWire ds(2); // Датчик или группа датчиков подключены к выводу D2 Arduino
// ФУНКЦИЯ ПРЕДВАРИТЕЛЬНЫХ УСТАНОВОК
void setup(void) { Serial.begin(9600);} // Инициализация работы с Serial-портом }
// ОСНОВНОЙ ЦИКЛ
void loop(void) {
byte i; // Вспомогательная переменная для циклов
byte present = 0; // Переменная для определения готовности датчика к общению
byte type_s; // Переменная для определения типа термодатчика на шине
byte data[12]; // Массив для хранения принятой от датчика информации
byte addr[8]; // Массив для хранения 64-битного адреса датчика
float celsius, fahrenheit; // Переменные для вычисления температуры
// Если устройства на шине не найдены или перебраны все устройтсва на шине
// выводим соответствующую информацию в монитор порта, сбрасываем очередь
// и осуществляем повторный поиск, выждав 250мС
if (!ds.search(addr)) {
Serial.println("No more addresses."); Serial.println();
ds.reset_search();
delay(250); return;
}
// Если очередное устройство на шине найдено, выводим его уникальный адрес
// в монитор порта в 16-тиричном виде
Serial.print("ROM =");
for( i = 0; i < 8; i++) { Serial.write(' '); Serial.print(addr[i], HEX); }
// Проверяем контрольную сумму адреса найденного устройства
// и если она не совпадает, выводим соответствующую инфорацию
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// Проверяем нулевой байт адреса, в котором содержится информация
// о конкретном типе температурного датчика. В зависимости от значения нулевого
// байта, выводим в монитор порта серию чипа. Если нулевой байт содержит неизвестное
// значение - выводим сообщение о неизвестном семействе термодатчика.
switch (addr[0]) {
case 0x10: Serial.println(" Chip = DS18S20"); type_s = 1; break;
case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break;
case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break;
default: Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.reset(); // Сбрасываем шину для инициализации обмена данными
ds.select(addr); // Выбираем датчик с текущим адресом для работы с ним
// Подаём команду на преобразование температуры (по документации 0х44)
// Не забываем про второй параметр "1", так как мы передаём данные по
// линии с паразитным питанием.
ds.write(0x44, 1);
// Датчик начинает преобразование, которое согласно документации занимает макс. 750мС
// Для перестраховки организовуем паузу, длительностью в ё секунду
delay(1000);
// Повторно сбрасываем шину для считываения информации с датчика
// сохраняем ответ функции reset() в переменную present для дальнейшой работы с ней
present = ds.reset();
ds.select(addr);// Повторно выбираем датчик по его адресу, так как был импульс сброса
// Команда 0хBE согласно технической документации, разрешает чтение внутренней памяти
// термодатчика (Scratchpad), которая состоит из 9-ти байт.
ds.write(0xBE);
// Считываем и выводим в монитор порта 9 байт из внутренней памяти термодатчика
Serial.print(" Data = "); Serial.print(present, HEX); Serial.print(" ");
for (i = 0; i < 9; i++) {
data[i] = ds.read();
Serial.print(data[i], HEX); Serial.print(" ");
}
// Проверяем и выводим в монитор порта контрольую сумму полученных данных
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// Начинаем процесс преобразования полученых данных в фактическую температуру,
// которая храниться в 0 и 1 байтах считанной памяти. Для этого объединяем эти два
// байта в одно 16-ти битное число
int16_t raw = (data[1] << 8) | data[0];
// Перед дальнейшим преобразованием, на потребуется определить семейство, к которому
// относится данный датчиик (ранее мы сохраняли релультат в переменной type_s).
// В зависимости от семейства, вычисление температуры будет проходить по-разному,
// так как DS18B20 и DS1822 возвращают 12-ти битное значение, а DS18S20 - 9-ти битное
if (type_s) { // Если датчик относится к семейтсву DS18S20
raw = raw << 3; // разрешение по умолчанию равно 9 бит
if(data[7] == 0x10) {
raw = (raw & 0xFFF0) + 12 - data[6];
}
}
else {
// Определяем на какую точночть измерения сконфигурирован данный датчик
byte cfg = (data[4] & 0x60);
// При более низких разрешениях можно обнулять младшие биты,
// так как они всё-рано не определены
if (cfg == 0x00) raw = raw & ~7; // 9 бит (преобразование занимает 93.75 ms)
else if (cfg == 0x20) raw = raw & ~3; // 10 бит (преобразование занимает 187.5 ms)
else if (cfg == 0x40) raw = raw & ~1; // 11 бит (преобразование занимает 375 ms)
// По умолчанию установлена точность 12 бит (преобразование занимает 750 ms)
}
// Вычисляем и выводим значения температуры в монитор порта
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = ");
Serial.print(celsius); Serial.print(" Celsius, ");
Serial.print(fahrenheit); Serial.println(" Fahrenheit");
}