GyverLibs / GyverDS18

Лёгкая библиотека для термометров Dallas DS18b20, обновлённая и более удобная версия библиотеки microDS18B20
MIT License
3 stars 1 forks source link

latest PIO Foo Foo Foo

Foo

GyverDS18

Лёгкая библиотека для термометров Dallas DS18b20, обновлённая и более удобная версия библиотеки microDS18B20.

Совместимость

Совместима со всеми Arduino платформами (используются Arduino-функции)

Зависимости

GyverIO

Содержание

Подключение

scheme P.S. Вместо резистора на 4.7к можно использовать параллельно два по 10к =)

Для режима "паразитного питания" нужно замкнуть VCC и GND датчика. Пин МК так же должен быть подтянут к питанию!

Использование

Инициализация

// один датчик на пине
GyverDS18Single();
GyverDS18Single(uint8_t pin, bool parasite = true);

// прямая адресация
GyverDS18();
GyverDS18(uint8_t pin, bool parasite = true);

// массив адресов
GyverDS18Array();
GyverDS18Array(uint8_t pin, uint64_t* addr = nullptr, uint8_t amount = 0, bool parasite = true);

Описание классов

// установить пин
void setPin(uint8_t pin);

// включить режим паразитного питания (умолч. вкл)
void setParasite(bool parasite);

// установить разрешение (9.. 12 бит)
bool setResolution(uint8_t res);

// прочитать разрешение
uint8_t readResolution();

// прочитать адрес датчика. 0 - ошибка
uint64_t readAddress();

// прочитать питание: DS18_PARASITE - паразитное, DS18_EXTERNAL - обычное, 0 - ошибка
uint8_t readPower();

// получить текущее время измерения температуры, мс
uint16_t getConversionTime();

// ===================== TEMP =====================

// запросить температуру
bool requestTemp();

// true - температура готова (асинхронно)
bool ready();

// true - температура готова (ждать)
bool waitReady();

// true - идёт ожидание конвертации
bool isWaiting();

// прочитать температуру
bool readTemp();

// получить "сырую" температуру (умножена на 16)
int16_t getTempRaw();

// получить int температуру
int16_t getTempInt();

// получить float температуру
float getTemp();

// ===================== MANUAL =====================

// прочитать содержимое оперативной памяти в буфер 5 байт
bool readRAM(uint8_t* buf);

// записать данные в оперативную память (th, tl)
bool writeRAM(uint8_t b0, uint8_t b1);

// записать содержимое оперативной памяти в EEPROM
bool copyRAM();

// записать содержимое EEPROM в оперативную память
bool recallRAM();

// применить разрешение
void applyResolution(uint8_t res);

Отличия в классе GyverDS18 - нужно передавать адрес датчика:

bool setResolution(uint8_t res);    // установить у всех
bool setResolution(uint8_t res, uint64_t addr);
uint8_t readResolution(uint64_t addr);
uint8_t readPower(uint64_t addr);
bool requestTemp();     // запросить у всех
bool requestTemp(uint64_t addr);
bool readTemp(uint64_t addr);
bool readRAM(uint8_t* buf, uint64_t addr);
bool writeRAM(uint8_t b0, uint8_t b1, uint64_t addr);
bool copyRAM(uint64_t addr);
bool recallRAM(uint64_t addr);

Отличия в классе GyverDS18Array - нужно передавать индекс датчика в массиве:

// подключить массив адресов формата uint64_t[]
void setAddress(uint64_t* addr, uint8_t amount);

// получить количество адресов в массиве
uint8_t amount();

bool setResolution(uint8_t res);    // установить у всех
bool setResolution(uint8_t res, uint8_t index);
uint8_t readResolution(uint8_t index);
uint8_t readPower(uint8_t index);
bool requestTemp();     // запросить у всех
bool requestTemp(uint8_t index);
bool readTemp(uint8_t index);
bool readRAM(uint8_t* buf, uint8_t index);
bool writeRAM(uint8_t b0, uint8_t b1, uint8_t index);
bool copyRAM(uint8_t index);
bool recallRAM(uint8_t index);

Дополнительные функции

// прочитать разрешение из внешнего буфера (5 байт)
uint8_t gds::calcResolution(uint8_t* buf);

// прочитать температуру из внешнего буфера (5 байт)
int16_t gds::calcTemp(uint8_t* buf);

// копировать адрес в буфер размером 8
void gds::copyAddress(uint64_t address, uint8_t* buf);

// вывести адрес в Print
void gds::printAddress(uint64_t address, Print& p, bool newline = true);

// вывести адрес в String
String gds::addressToString(uint64_t address);

Один датчик

Для работы с одним датчиком на пине используется класс GyverDS18Single. Температура получается в четыре этапа:

Примечание: сразу после включения датчик имеет в буфере температуру 85 градусов. Если не запросить температуру - будет прочитана температура 85 градусов. Поэтому в библиотеке игнорируется значение 85 градусов, датчики можно подключать "на горячую" и не бояться, что где то в программе резко появится цифра 85.

В библиотеке есть встроенный асинхронный таймер на время конвертации, базовый пример циклической работы с датчиком выглядит так:

#include <GyverDS18.h>
GyverDS18Single ds(2);  // пин

void setup() {
    Serial.begin(115200);
    ds.requestTemp();  // первый запрос на измерение
}
void loop() {
    if (ds.ready()) {         // измерения готовы по таймеру
        if (ds.readTemp()) {  // если чтение успешно
            Serial.print("temp: ");
            Serial.println(ds.getTemp());
        } else {
            Serial.println("error");
        }

        ds.requestTemp();  // запрос следующего измерения
    }
}

Примечание: readTemp() именно читает температуру с датчика, а getTemp() - возвращает результат из буфера библиотеки. Таким образом можно вызывать getTemp() несколько раз подряд, если это нужно (после вызова readTemp())

Для запуска первой конвертации также можно использовать статус isWaiting():

void loop() {
    // запросить конвертацию
    if (!ds.isWaiting()) ds.requestTemp();

    // получить и вывести
    if (ds.ready()) {
        if (ds.readTemp()) Serial.println(ds.getTemp());
        // здесь статус waiting будет сброшен
    }
}

Для синхронной работы (с ожиданием) можно использовать такую конструкцию:

ds.requestTemp();   // запросить

if (ds.waitReady() && ds.readTemp()) {  // подождать, затем прочитать
    Serial.print("temp: ");
    Serial.println(ds.getTemp());
} else {
    Serial.println("error");
}

Обращение по адресу

Можно подключить несколько датчиков на один пин. Для обращения к датчикам нужно знать их уникальные адреса, поэтому сначала нужно получить адрес. Для этого нужно подключить один датчик к пину и вызвать readAddress(). Примечание: корректный адрес никогда не может быть равен 0, это можно использовать для проверки корректности.

В данной библиотеке, в отличие от многих других, адрес представлен типом uint64_t - более удобном для записи и хранения. На AVR Arduino такой тип не выводится в Serial. Для вывода можно использовать встроенную функцию gds::printAddress

#include <GyverDS18.h>
GyverDS18Single ds(2);  // пин

void setup() {
    Serial.begin(115200);

    uint64_t addr = ds.readAddress();
    if (addr) {
        Serial.print("address: ");
        gds::printAddress(addr, Serial);
        // пример вывода: 0xCF0417505B78FF28
    } else {
        Serial.println("error");
    }
}

void loop() {
}

Для обращения к датчикам по адресам используется класс GyverDS18:

#include <GyverDS18.h>
GyverDS18 ds(2);  // пин

uint64_t addr = 0xCF0417505B78FF28;

void setup() {
    Serial.begin(115200);
    // первый запрос на измерение. Запрос ВСЕМ датчикам на линии
    ds.requestTemp();
}
void loop() {
    if (ds.ready()) {             // измерения готовы по таймеру
        // читаем КОНКРЕТНЫЙ датчик по адресу
        if (ds.readTemp(addr)) {  // если чтение успешно
            Serial.print("temp: ");
            Serial.println(ds.getTemp());
        } else {
            Serial.println("error");
        }

        ds.requestTemp();  // запрос следующего измерения ДЛЯ ВСЕХ
    }
}

Примечания:

Несколько датчиков

Для удобного взаимодействия с несколькими датчиками есть класс GyverDS18Array. Пример чтения "связки" датчиков:

#include <GyverDS18Array.h>

uint64_t addr[] = {
    0xD20417515A42FF28,
    0x4D0417508099FF28,
    0xFE04175159CDFF28,
    0xCF0417505B78FF28,
};
GyverDS18Array ds(2, addr, 4);  // пин, массив, длина

void setup() {
    Serial.begin(115200);
    // Запрос ВСЕМ датчикам на линии
    ds.requestTemp();
}
void loop() {
    if (ds.ready()) {  // измерения готовы по таймеру
        // проходим по массиву
        for (int i = 0; i < ds.amount(); i++) {
            Serial.print("#");
            Serial.print(i);
            Serial.print(": ");
            // читаем по индексу
            if (ds.readTemp(i)) Serial.print(ds.getTemp());
            else Serial.print("error");
            Serial.print(", ");
        }
        Serial.println();

        ds.requestTemp();  // запрос следующего измерения ДЛЯ ВСЕХ
    }
}

Работа с памятью датчика

Датчик имеет 2 байта EEPROM памяти (не сбрасывается при перезагрузке), их можно использовать в каких-то своих сценариях. Например записывать туда калибровку или что то ещё. Важный момент: запись этих данных пересекается с установкой разрешения датчика, поэтому установленное разрешение хранится в библиотеке и само записывается при отправке, причём функция setResolution() сбрасывает эти два байта. Для записи используется функция writeRAM(), которая также перезаписывает разрешение. Сценарий записи своих данных и желаемого разрешения:

// данная функция не устанавливает разрешение, 
// а просто запоминает его в библиотеке
ds.applyResolution(12);

// запись данных в RAM (оперативную память)
// здесь мы пишем два своих байта данных, и здесь же устанавливается разрешение,
// заданное в applyResolution() или setResolution()
ds.writeRAM(0xAB, 0xCD);

// можно сохранить данные в EEPROM датчика при помощи отдельной функции
ds.copyRAM();

// и прочитать из EEPROM обратно в RAM
// при запуске датчика они читаются автоматически!
ds.recallRAM();

Чтение данных из памяти производится в буфер размером 5, в этом буфере будет температура (байты 0 и 1), данные (байты 2 и 3) и разрешение (байт 4). Таким образом за одно обращение к датчику можно вытащить все нужные данные, особенно полезно если там хранится калибровка - можно сразу её применить:

uint8_t buf[5];
ds.readRAM(buf);
Serial.println(buf[2], HEX);    // первый байт
Serial.println(buf[3], HEX);    // второй байт

Serial.println(gds::calcTemp(buf) / 16.0);  // вывести температуру
Serial.println(gds::calcResolution(buf));   // вывести разрешение

Версии

Установка

Баги и обратная связь

При нахождении багов создавайте Issue, а лучше сразу пишите на почту alex@alexgyver.ru
Библиотека открыта для доработки и ваших Pull Request'ов!

При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать: