Захотелось мне тут порезвиться с этой замечательной микросхемой. И так как я страдаю фигнёй манией писать библиотеки для разного вида подобных устройств, библиотека была написана! Писал долго, потому как было мало свободного времени. К тому же очень хотелось чтобы она поддерживала весь функционал доступный программисту. А функционал у неё неплохой. Микруха такая стоит порядка 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 от производителя;