Захотелось мне тут порезвиться с этой замечательной микросхемой. И так как я страдаю фигнёй манией писать библиотеки для разного вида подобных устройств, библиотека была написана! Писал долго, потому как было мало свободного времени. К тому же очень хотелось чтобы она поддерживала весь функционал доступный программисту. А функционал у неё неплохой. Микруха такая стоит порядка 150-300руб. (как повезёт), и имеет следующие основные возможности:
- Работа по интерфейсу 1-wire, который требует всего одной линии для связи с МК;
- Возможность питания от одной линии данных;
- Уникальный 64-битный ID для каждого датчика;
- Возможность развёртывать целые микросети таких датчиков связанных одной шиной;
- Неплохая точность, ±0.5°C в диапазоне -10°C до 85°C;
- Оповещение о выходе температуры из заданных пределов;
- Совместимость с DS1822;
Варианты подключения
Может питаться как от внешнего источника, так и от линии данных. На следующих рисунках показаны варианты подключения (слева-направо) от внешнего источника, от шины данных.
Особенности библиотеки
Разработанная библиотека поддерживает все возможности данного цифрового термометра, и занимает в памяти МК от 254 до 918 байт, в зависимости от выбранных настроек конфигурации. В минимальной конфигурации поддерживается:
- Измерение температуры (convert);
- Чтение температуры (readTemp);
- Выбор датчика по его уникальному коду (selectSensor);
Полный вариант конфигурации поддерживает к тому же:
- Дополнительные функции (такие как recall, readScratchpad, copyScratchpad, writeScratchpad, и др.);
- Автоматическая проверка контрольной суммы при приёме данных;
- Поддержка датчиков питающихся паразитным током;
- Поиск устройств на шине а также датчиков чья температура выходит из заданных пределов (searchROM, searchAlarm);
- Дополнительные функции для обработки значения температуры, с целью дальнейшего вывода на дисплей (extractInt, extractFract);
Примеры использования
Простой пример демонстрирующий вывод текущего значения температуры на дисплей:
#include "wh1602b/wh1602b.h"
#include "ds18b20/ds18b20.h"
#include <avr/pgmspace.h>
void conf_my_lcd();
void loop();
int main(void)
{
conf_my_lcd(); // настроить вывод на жк-дисплей
// выбрать текущий датчик (0 т.к. единственный у меня)
if (!ds18b20_selectSensor(0)) {
wh1602b_putsP(PSTR("Ошибка на линии!"));
for (;;)
;
}
for (;;)
loop(); // цикл обработки
}
void loop()
{
ds18b20_convert(); // попросить у датчика измерить температуру
wh1602b_move(0,0);
wh1602b_putsP(PSTR("t="));
int16_t t = ds18b20_readTemp(); // прочитать значение
if (t < 0) // вывести минус если отрицательно
wh1602b_putc('-');
wh1602b_puth(1, ds18b20_extractInt(t)); // вывести целую часть на дисплей
wh1602b_putc('.');
wh1602b_puth(1, ds18b20_extractFract(t, 1)); // вывести дробную часть на дисплей
wh1602b_putsP(PSTR("\1C"));
}
// <...>
Вот что получилось:
Следующий пример демонстрирует вывод уникального кода микросхемы на дисплей:
#include "wh1602b/wh1602b.h"
#include "ds18b20/ds18b20.h"
#include <avr/pgmspace.h>
void conf_my_lcd();
int main(void)
{
conf_my_lcd(); // настроить вывод на жк-дисплей
uint8_t id[8];
if (!ds18b20_readROM(id)) { // прочитать уникальный код датчика в id
wh1602b_putsP(PSTR("Ошибка CRC!")); // если ошибка
for (;;)
;
}
wh1602b_putsP(PSTR("ROM Code ="));
wh1602b_move(1,0);
uint8_t i;
for (i = 0; i < 8; ++i)
wh1602b_puth(2, id[i]);
for (;;)
;
}
// <...>
И результат:
Следующий пример демонстрирует поиск устройств на шине:
#define F_CPU 20000000ULL /* частота мк, гц (для delay) */
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "wh1602b/wh1602b.h"
#include "ds18b20/ds18b20.h"
void conf_my_lcd();
void loop();
int main(void)
{
conf_my_lcd(); // настроить вывод на жк-дисплей
for (;;)
loop(); // цикл обработки
}
void loop()
{
uint8_t i, dc = 0, id[8];
int8_t r;
// поиск устройств на шине 1-wire
while ((r = ow_searchROM(id))) {
if (r < 0)
continue; // повтор если ошибка crc
wh1602b_move(0,0);
// вывести уникальный код датчика на дисплей
for (i = 0; i < 8; ++i)
wh1602b_puth(2, id[i]);
_delay_ms(2000); // пауза 2с.
++dc;
}
wh1602b_move(1,0);
wh1602b_putn(dc); // вывести число датчиков
wh1602b_putsP(PSTR(" devices."));
}
// <...>
И результат в моём случае:
Больше примеров можно будет найти в архиве с библиотекой, ссылка на который указана в разделе "скачать".
Настройка конфигурации
Перед компиляцией библиотеки необходимо задать порты к которым подключён дисплей, а также включаемые возможности. Для этого необходимо отредактировав файл ds18b20/conf.h:
#define F_CPU 20000000 /* частота мк, Гц */
#define USE_EXTRACTINT /* поддержка ds18b20_extractInt() */
#define USE_EXTRACTFRACT /* поддержка ds18b20_extractFract() */
// поддержка автоматической проверки данных контрольной суммой
#define SUPPORT_CHECKSUM
// поддержка возможности поиска устройств на шине
#define SUPPORT_ROMSEARCH
// поддержка датчиков питающихся паразитным током
#define SUPPORT_PARASITE_MODE
// поддержка некоторых дополнительных функций
#define SUPPORT_COMPLETE
/* порт к которому подключена линия данных */
#define DDR_SENSOR _SFR_IO_ADDR(DDRD)
#define PIN_SENSOR _SFR_IO_ADDR(PIND)
#define PORT_SENSOR _SFR_IO_ADDR(PORTD)
/* ножка к которой подключена линия данных */
#define NPIN_SENSOR PD2
Убрать лишние возможности тем самым уменьшив размер занимаемый библиотекой в памяти МК, можно закомментировав некоторые из строчек начинающихся с #define.
Полный перечень поддерживаемых функций
- uint8_t ds18b20_selectSensor(const uint8_t id[8])
Выбирает текущий датчик по его уникальному коду id. Если id = 0, то выбирается первое попавшееся устройство, которое должно быть единственным в сети. Если возвращаемое значение = 0, то вероятно линия данных не правильно настроена. В случае успеха возвращается значение > 0.
- void ds18b20_convert()
Отправляет команду текущему датчику чтобы тот начал измерение температуры.
- uint8_t ds18b20_readROM(uint8_t id[8])
Загружает уникальный код датчика в массив указанный аргументом id. В сети должно находиться только одно устройство, иначе возникнут коллизии. Если возвращаемое значение = 0, то вероятно линия данных не правильно настроена. В случае успеха возвращается значение > 0.
- int16_t ds18b20_readTemp()
Возвращает измеренное значение температуры текущего датчика в градусах. Младшие 4 бита определяют дробную часть, остальная часть - целое значение.
Например, если возвращаемое значение = 0x0191 = 0000000110010001 = 2^4+2^3+2^0+2^-4 = +25.0625°C
- uint8_t ds18b20_readPowerSupply()
Возвращает 1 если текущий датчик использует внешнее питание, 0 - питание от линии данных (паразитное).
- uint8_t ds18b20_readScratchpad(sspad* p)
Загружает состояние внутренней памяти текущего датчика в *p. Проверяется контрольная сумма, и возвращается значение > 0 в случае успеха. Если 0, то вероятно контрольная сумма не совпала, либо линия данных не правильно настроена.
Структура sspad определена в файле ds18b20/ds18b20.h и имеет следующее представление:
typedef struct {
uint8_t t_lsb; // temperature LSB
uint8_t t_msb; // temperature MSB
int8_t t_h; // Th register
int8_t t_l; // Tl register
uint8_t config; // configuration register
uint8_t reserved[3]; // reserved
} sspad;
Подробней о назначении каждого параметра можно почитать в официальной документации к ds18b20.
- void ds18b20_writeScratchpad(const sspad* p)
Записывает данные в *p в память текущего датчика.
- void ds18b20_copyScratchpad()
Копирует состояние памяти текущего датчика в его eeprom. EEPROM определяется как энергонезависимая память, и при каждом включении питания, данные из eeprom датчика будут загружаться в его оперативную память.
- void ds18b20_recall()
Восстанавливает состояние памяти текущего датчика из его eeprom.
- int8_t ow_searchROM(uint8_t id[8])
Выполняет поиск следующего из устройств на шине 1-wire, и передаёт его уникальный код в параметр на который указывает id. Если возвращаемое значение = 0, то поиск завершён. Если возвращаемое значение = -1, то это означает что контрольная сумма не совпала, и данные были повреждены при приёме. В случае успеха возвращается значение > 0.
- int8_t ds18b20_searchAlarm(uint8_t id[8])
Выполняет поиск следующего датчика у которого пороговое значение температуры вышло из заданных пределов, и передаёт его уникальный код в параметр на который указывает id. Если возвращаемое значение = 0, то поиск завершён. Если возвращаемое значение = -1, то это означает что контрольная сумма не совпала, и данные были повреждены при приёме. В случае успеха возвращается значение > 0.
- uint16_t ds18b20_extractInt(int16_t t)
Возвращает целую часть значения температуры из двухбайтовой величины t, получаемой при помощи вызова функции readTemp. Возвращаемое значение является абсолютным и представлено в двоично-десятичном формате (bcd).
- uint16_t ds18b20_extractFract(int16_t t, uint8_t r)
Возвращает дробную часть значения температуры из двухбайтовой величины t, получаемой при помощи вызова функции readTemp, округляя его до 1/10^r. Возвращаемое значение является абсолютным и представлено в двоично-десятичном формате (bcd).
Совместимость
Думаю что библиотека будет совместима с большинством микроконтроллеров AVR серии Mega (в моём случае был использован Atmega644).
Скачать
- Исходный код библиотеки вместе с примером можно скачать здесь (или здесь). Лицензия GNU GPL v3+;
- Официальная документация по ds18b20 от производителя;