Термодатчик ds18b20 схема

Термодатчик ds18b20 схема
Термодатчик ds18b20 схема
Термодатчик ds18b20 схема
Термодатчик ds18b20 схема
Обновлено 21.01.14. Исходники переписаны под AVR Studio 6 (с тулчейном)

Сразу хочу сообщить, что в этой статье я не буду описывать принцип работы шины (описание временных слотов и т.д.). Статья будет типа «Быстрый старт». Конкретно: я выложу свою библиотеку для работы с 1-wire, опишу как ею пользоваться, как подключить устройства к шине, как производить поиск устройств, передавать данные и т.д. А так, как (вероятно) 70% радиолюбителей в первую очередь решит подключить к шине термодатчик DS18B20, я выложу библиотеку для работы с DS18B20, где надо тупо запустить преобразование, подождать пока идет преобразование и записать температуру в массив.

Теория

Итак, 1-wire(еще называют MicroLAN, dallas-wire) так назвали потому что для передачи данных в обе стороны используется только 1 провод. Среди самых популярных устройств, работающих на этой шине можно выделить термодатчик DS18B20 и электронный ключ DS1990 (которым вы в подъезде двери открываете). У сети 1-wire есть одно ведущее устройство(Master) и несколько (или 1) подчиненных (Slave). Бывают сети с несколькими ведущими, по это нам сейчас не нужно. Передачу данных начинает ведущий, только он может посылать сигнал сброса (Reset), остальные устройства могут только отвечать на его запросы. Все устройства подключаются к шине параллельно, то есть, линию данных с каждого устройства (она обозначается DATA, DQ или OW_DQ), включая линию ведущего, подключают к одному проводу, типа вот так: 

Еще линия должна быть подтянута к питанию через резистор 2,2-4,7 кОм. Каждое устройство имеет свой индивидуальный 64-битный адрес, который устанавливается при изготовлении устройства (прямо на заводе).

Практика

Работать с 1-wire мне приходится очень часто, поэтому, я написал безглючную библиотеку, которая имеет кучу функций, включая возможность эмуляции 1-wire с помощью USART. К тому же, библиотека стабильно работает даже в протеусе. Многие говорят, что 1-wire слишком медленный, а из-за того, что он требует очень точных временных задержек (в несколько микросекунд), с ним практически не возможно работать, если в микроконтроллере часто вызываются прерывания. Действительно, если одновременно использовать софтовый USB (V-USB) и 1-wire, то что то одно с них не будет стабильно работать. Я решил эту проблему эмуляцией 1-wire через USART микроконтроллера. Поэтому, если у вас будет свободный USART, то 1-wire обязательно вешайте на него. Как же будем подключать устройства? Я использую три (уже 4) способа. Первый. Эмуляция USARTом. Если вы используете длинную линию (более 20 метров) и более 4 устройств на шине, то подключать нужно вот так: Здесь сигнал усиливается с помощью двух транзисторов. На шине стоит метка OW_DQ, вот к ней и подключаем подчиненные устройства. Если длина не более 20 метров, то можно подключить вот так:Здесь резистор может быть номиналом 2,2 — 4,7 кОм. Если вы не используете USART для эмуляции 1-wire, то подключать нужно так:Здесь одна ножка МК работает в качестве и входа, и выхода. Есть еще и четвертый способ, подключение как на первом, только для эмуляции не используется USART, но мне этот способ ни разу не понадобился. Давайте теперь соберем схему в протеусе (можете скачать в прикрепленных файлах). USART будет занят терминалом, поэтому шина будет подключена по третьем способу. В качестве ведущего — ATMega8, подчиненные — термодатчики DS18B20 и DS18S20, память EEPROM на 256 Кбит, таблетка, DS18B20 и двухканальный ключ DS2413. Так же, на схеме есть терминал, в котором будут отображаться данные.

Код

Скачайте прикрепленные файлы и откройте onewire.h. В нем есть строка

#define MAXDEVICES 10

#define MAXDEVICES 10

Здесь указывается максимальное количество подчиненных устройств, которые будет искать подчиненный, если выберите меньше, чем подключено, то просто не будут обнаружены все устройства, если больше — то увеличиться время процедуры поиска. Но лучше ставьте с запасом, при 32 поиск занимает не более двух секунд (а может и меньше секунды).

#define UART_AS_OneWire

#define UART_AS_OneWire

Если вы не используете эмуляцию 1-wire через USART, то закомментируйте эту строку.

#define OW_DDR DDRB #define OW_PORT PORTB #define OW_PIN PINB #define OW_BIT 0

#define OW_DDR DDRB #define OW_PORT PORTB #define OW_PIN PINB #define OW_BIT 0

Если не используется эмуляция, укажите здесь куда подключен 1-wire. В том же файле есть несколько функций:

unsigned char OW_Reset(void); void OW_WriteBit(unsigned char bit); unsigned char OW_ReadBit(void); unsigned char OW_ReadByte(void); void OW_WriteByte(unsigned char byte); unsigned char OW_SearchROM( unsigned char diff, unsigned char id ); void OW_FindROM(unsigned char diff, unsigned char id[]); unsigned char OW_ReadROM(unsigned char buffer); unsigned char OW_MatchROM(unsigned char rom);

unsigned char OW_Reset(void); void OW_WriteBit(unsigned char bit); unsigned char OW_ReadBit(void); unsigned char OW_ReadByte(void); void OW_WriteByte(unsigned char byte); unsigned char OW_SearchROM( unsigned char diff, unsigned char id ); void OW_FindROM(unsigned char diff, unsigned char id[]); unsigned char OW_ReadROM(unsigned char buffer); unsigned char OW_MatchROM(unsigned char rom);

По названию функции можно определить их предназначение, поэтому не стоит их описывать. В исходниках откройте главный файл (main.c). Здесь есть функция search_ow_devices(), она производит поиск устройств на шине и записывает их адреса в многомерный массив owDevicesIDs[MAXDEVICES][8], возвращает количество найденных устройств. Вот главная функция:

int main(void) { stdout = &usart_str; // указываем, куда будет выводить printf DDRB = 0b00000000; PORTB = 0b00000000; DDRC = 0b00000000; PORTC = 0b00000000; DDRD = 0b00000010; PORTD = 0b00000000; USART_init(); // включаем uart timerDelayInit(); nDevices = search_ow_devices(); // ищем все устройства printf("---------- Found %d devices ----------", nDevices); for (unsigned char i=0; i<nDevices; i++) // теперь сортируем устройства и запрашиваем данные { // узнать устройство можно по его груповому коду, который расположен в первом байте адресса switch (owDevicesIDs[i][0]) { case OW_DS18B20_FAMILY_CODE: { // если найден термодатчик DS18B20 printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Thermometer DS18B20"); // печатаем тип устройства DS18x20_StartMeasureAddressed(owDevicesIDs[i]); // запускаем измерение timerDelayMs(800); // ждем минимум 750 мс, пока конвентируется температура unsigned char data[2]; // переменная для хранения старшего и младшего байта данных DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные unsigned char themperature[3]; // в этот массив будет записана температура DS18x20_ConvertToThemperature(data, themperature); // преобразовываем температуру в человекопонятный вид printf(": %d.%d C", themperature[1],themperature[2]); } break; case OW_DS18S20_FAMILY_CODE: { // если найден термодатчик DS18B20 printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Thermometer DS18S20"); // печатаем тип устройства } break; case OW_DS1990_FAMILY_CODE: { // если найден электронный ключ DS1990 printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Serial button DS1990"); // печатаем тип устройства } break; case OW_DS2430_FAMILY_CODE: { // если найдена EEPROM printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - EEPROM DS2430"); // печатаем тип устройства } break; case OW_DS2413_FAMILY_CODE: { // если найден ключ printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Switch 2413"); // печатаем тип устройства } break; } } while(1){} }

int main(void) { stdout = &usart_str; // указываем, куда будет выводить printf DDRB = 0b00000000; PORTB = 0b00000000; DDRC = 0b00000000; PORTC = 0b00000000; DDRD = 0b00000010; PORTD = 0b00000000; USART_init(); // включаем uart timerDelayInit(); nDevices = search_ow_devices(); // ищем все устройства printf("---------- Found %d devices ----------", nDevices); for (unsigned char i=0; i<nDevices; i++) // теперь сортируем устройства и запрашиваем данные { // узнать устройство можно по его груповому коду, который расположен в первом байте адресса switch (owDevicesIDs[i][0]) { case OW_DS18B20_FAMILY_CODE: { // если найден термодатчик DS18B20 printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Thermometer DS18B20"); // печатаем тип устройства DS18x20_StartMeasureAddressed(owDevicesIDs[i]); // запускаем измерение timerDelayMs(800); // ждем минимум 750 мс, пока конвентируется температура unsigned char data[2]; // переменная для хранения старшего и младшего байта данных DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные unsigned char themperature[3]; // в этот массив будет записана температура DS18x20_ConvertToThemperature(data, themperature); // преобразовываем температуру в человекопонятный вид printf(": %d.%d C", themperature[1],themperature[2]); } break; case OW_DS18S20_FAMILY_CODE: { // если найден термодатчик DS18B20 printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Thermometer DS18S20"); // печатаем тип устройства } break; case OW_DS1990_FAMILY_CODE: { // если найден электронный ключ DS1990 printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Serial button DS1990"); // печатаем тип устройства } break; case OW_DS2430_FAMILY_CODE: { // если найдена EEPROM printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - EEPROM DS2430"); // печатаем тип устройства } break; case OW_DS2413_FAMILY_CODE: { // если найден ключ printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Switch 2413"); // печатаем тип устройства } break; } } while(1){} }

В начале у нас идет инициализация периферии, затем, производится поиск устройств на шине и найденное количество записывается в переменную nDevices. Далее, в цикле for определяется тип устройства (его можно определить по первом байту адреса). В терминале протеуса печатается адрес каждого устройства и его тип: Как видите, напротив DS18B20 написана еще и его температура, глянем в код:

printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Thermometer DS18B20"); // печатаем тип устройства DS18x20_StartMeasureAddressed(owDevicesIDs[i]); // запускаем измерение timerDelayMs(800); // ждем минимум 750 мс, пока конвентируется температура unsigned char data[2]; // переменная для хранения старшего и младшего байта данных DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные unsigned char themperature[3]; // в этот массив будет записана температура DS18x20_ConvertToThemperature(data, themperature); // преобразовываем температуру в человекопонятный вид printf(": %d.%d C", themperature[1],themperature[2]);

printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес printf(" - Thermometer DS18B20"); // печатаем тип устройства DS18x20_StartMeasureAddressed(owDevicesIDs[i]); // запускаем измерение timerDelayMs(800); // ждем минимум 750 мс, пока конвентируется температура unsigned char data[2]; // переменная для хранения старшего и младшего байта данных DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные unsigned char themperature[3]; // в этот массив будет записана температура DS18x20_ConvertToThemperature(data, themperature); // преобразовываем температуру в человекопонятный вид printf(": %d.%d C", themperature[1],themperature[2]);

В первых двух строчках просто печатается адрес устройства и его тип. Затем, запускается измерение с помощью функции DS18x20_StartMeasureAddressed(owDevicesIDs[i]);. В эту функцию передается массив с адресом устройства. Далее, нужно подождать 750 мс, пока конвертируется температура, после чего, считываем данные с устройства DS18x20_ReadData(owDevicesIDs[i], data);. В функцию передается указатель на массив с адресом и указатель на массив, в который надо записать результат (2 байта). Теперь надо перевести эти 2 байта в человекопонятный вид, то есть, «знак, целая часть, запятая, десятая часть», это делает функция DS18x20_ConvertToThemperature(data, themperature);. Кстати, совсем не обязательно для запуска измерения температуры передавать адрес устройства, можно просто написать DS18x20_StartMeasure(). Тогда преобразование запустится на всех DS18B20, которые подключены к шине, спустя 750мс можно считать данные по очереди со всех DS18B20 без задержки. Так же, если используете эмуляцию 1-wire через USART, то обязательно устанавливайте не только DDR пина TX, а и PORT, иначе обмен на шине будет запускаться максимум в 30% случаев.

Обновление №1 (5.12.2011):

Добавил возможность подключения четвертым способом. Подключение такое же как в первых двух, но для эмуляции не используется USART. Этот способ стоит использовать если у Вас занят USART и линия длинней 15-20 метров. В файле onewire.h появились новая опция:

// Если для эмуляции 1-wire не спольльзуется USART, но используется 2 пина (вход и выход) #define OW_TWO_PINS

// Если для эмуляции 1-wire не спольльзуется USART, но используется 2 пина (вход и выход) #define OW_TWO_PINS

Также Вам стоит немного взглянуть сюда:

#ifndef OW_TWO_PINS //если используется один пин, укажите его номер #define OW_BIT 0 #else // если используются 2 пина, укажите их номера #define OW_BIT_OUT 1 #define OW_BIT_IN 0 #endif

#ifndef OW_TWO_PINS //если используется один пин, укажите его номер #define OW_BIT 0 #else // если используются 2 пина, укажите их номера #define OW_BIT_OUT 1 #define OW_BIT_IN 0 #endif

При настройке портов нужно установить DDR и PORT входа в 0, а выхода в 1.

Обновление №2 (3.1.2012):

Добавил возможность проверки CRC. Теперь функция DS18x20_ReadData() возвращает 0, если crc ошибочная. Зачем это нужно? Делал один проект, где на шине висит много датчиков и есть вероятность, что после прочтения адреса один из датчиков может быть отключен и система должна знать, что его нет, но функция DS18x20_ReadData() возвращает 1, если на шине есть любое устройство 1-wire, так как наличие устройства функция определяет с помощью функции OW_Reset(). Теперь с датчика считываются не только первые 2 байта, в которых температура, а все 9, вместе с контрольной суммой (CRC), контрольная сумма проверяется, и если она не совпала, то возвращается 0. Вопросы в комментариях.

Скачать исходники и проект в Proteus (84 Kb)

Ноябрь 17th, 2011 | Категория: Программирование AVR

Для связи

Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема Термодатчик ds18b20 схема

Статьи по теме:



Как сделать скины для навигатора

Схема усилителя на кт940а

Книга своими руками титульный лист

Подарки своими руками из бумаги кораблики

Мастер класс по вязанию детских кофты реглан спицами