3 датчика DS18B20+Arduino
- Войдите на сайт для отправки комментариев
Сб, 30/06/2012 - 20:22
Здравствуйте. У меня такой вопрос (прошу прощения если вопрос уже звучал на данном форуме, но, к сожалению, я не нашел на него ответа...):
- итак, имеется сама arduino, 3 датчика температуры DS18B20 (подключены параллельно). Температуру я с них вытаскиваю нормально, а вот конкретно с 1 или со 2 по запросу не могу узнать как это реализовать. Знаю что необходимо отправить запрос SEARCH ROM, но куда в коде это вставить? Вариант со считыванием адресов по одному и записью их в скетч не подходит. Код прилагаю.
#include <OneWire.h> OneWire ds (10); // все OneWire устройства на pin 10 int led_pin=13; // определили pin 13 для светодиода byte done[8]; void setup (void) { Serial.begin (9600); pinMode(led_pin, OUTPUT); } void loop (void) { byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; float celsius; if (ds.search (addr)!=1) { ds.reset_search (); delay (250); return; } ds.reset (); ds.select (addr); //Serial.print ((addr)[8]); //Serial.print (" "); ds.write (0x44,1); // start conversion, with parasite power on at the end delay (1000); // maybe 750ms is enough, maybe not // we might do a ds.depower () here, but the reset will take care of it. present = ds.reset (); ds.select (addr); ds.write (0xBE); // Read Scratchpad for (i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read (); } // convert the data to actual temperature unsigned int raw = (data[1] << 8) | data[0]; if (type_s) { raw = raw << 3; // 9 bit resolution default if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw << 3; // 9 bit resolution, 93.75 ms else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms } celsius = (float)raw / 16.0; //Serial.print ("Temperature = "); Serial.println (celsius); //Serial.print (" "); Serial.flush(); //очищаем значения порта }
Небольшое уточнение: все датчики подключены как уже сказано параллельно к 10 pin arduino для экономии. Позже планирую подключить 2х датчик DH11. С количеством пока не определился. Сейчас задача сводиться к тому, чтобы при выводе температуры отображалась информация типа: температура1 - 25.02 температура2 - 28.05 ....и т.д.
>если вопрос уже звучал на данном форуме
Вы правы - звучал. http://arduino.ru/forum/programmirovanie/onewire-vyvesti-adres-dlya-dalneishego-dlya-pryamoi-indeksatsii
Но и ваш скетч должен работать. Собственно говоря строчка 20 - что как ни поиск следующего девайса на шине? Сами же сказали "нужен search". ну дык это он и есть :) (вообщем при каждом проходе loop, оно должно следующий датчик смотреть, если больше не нашло - опять начинать с первого).
мой скетч работает, он показывает температуру со всех датчиков, при необходимости выводит все адреса, но не может определить и вывести температуру с определенного. Спасибо за пример, его я еще не видел, но в нем по-моему (не так давно занимаюсь программированием МК) другой алгоритм поиска, который я пока не понимаю.
>другой алгоритм поиска, который я пока не понимаю.
Нет. Там другая библиотека. Вернее "еще одна". Специально для этих датчиков температур. Но внутри себя они использует ту же самую OneWire библиотеку. Это просто удобная обертка над OneWire для данного конкретного случая (ну что-бы не нужно было помнить коды комманд и т.п.). Так что "механизм работы" у этих примеров - один и тот же.
OneWire - универсальная. С ее помощью можно работать с любым устройсвом (вкиснув в его даташит), а DallasTemperatureControl - частный случай для DS18B20
>необходимости выводит все адреса
> вывести температуру с определенного
Я, видимо, не совсем понимаю в чем проблема. Что вы понимаете под "определенный"?
По идее каждый адресс и позволяет обращатся к определенному датчику. Это есть его "определение".
Вообщем мы можем получить список всех доступных адресов, можем обратится с запросом к конкретному адресу, что еще нужно для счастья?
для данной системы датчиков разработан (пока минимальный функционал) сайт с базой данных. Счиитывая температуру, как сейчас (т.е. температура валиться подряд неизвестно от какого из датчиков) проблема состоит в том, что при записи температуры в БД нельзя определить откуда она взята, а в моем алгоритме (взят с какогото примера) нет возможности: посчитать датчии, определить сколько их на шине (актуально при увеличении их количества). Вместе с тем я хочу реализовать запро-ответ....например хочу узнать температуру 2 или 3 датчика, но пока не соображу как это сделать. Приведенный вами пример, к сожалению, у меня не работает, а ответа в интернете я, пока, нигде не нахожу. Буду признателен за помощь, для меня алгоритм (библиотека не принципаальна)
>что при записи температуры в БД нельзя определить откуда она взята
Ну так а что мешает кроме температуры выводить в сериал еще и адресс с которго она была прочитанна?
Насколько я понимаю закоменченные строки 28,29 и была попытка сделать это. Правда корявая. Скорее нужно что-типа
>нет возможности: посчитать датчии, определить сколько их на шине
Почему нет возможности? Что мешает setup() вызвать что-то типа while(ds.search (addr) )sensorCounter++
Загляните в файлик OneWire.h, почитайте что делают и что возвращают функции. В частности функция search
> Приведенный вами пример, к сожалению, у меня не работает,
Ну видимо сожаление не слишком большое, раз попыток решить проблему не предпринимается.
>а ответа в интернете я, пока, нигде не нахожу
Ну так "точного решения" вашей задачи вы и не найдете. Есть, конечно, вероятность что кто-то делал что-то "в точности то же что и вы", но шансы такое найти... . Реализовывать свою логику "запрос-ответ" прийдется самому. В инете нет скетчей на все случая жизни :)
А "в общем" в инете (и в примерах/документации) все описанно. Как опрашивать датчики, как работать с serail портом. А вот "как соеденить" все это - это уже забота автора скетча. Если с этим большие проблемы, то может стоит какую-нибудь книжечку по программированию почитать (или хотя-бы раздел http://arduino.ru/Reference прочитать/освоится). Потому, несмотря на маркетинг, для исползования арудуины "немного программинга" все равно нужно освобить (хотя бы разобратся с переменными, и управляющими операторами).
видими придется и адрес датчика определять.
>Насколько я понимаю закоменченные строки 28,29 и была попытка сделать это. Правда корявая. Скорее нужно что-типа
это остатки кода в котром пробовал считать количество устройств. За предложенный вариант благодарен, но он у меня есть (я пока его убрал).
uint8_t OneWire::search(uint8_t *newAddr)
данная функция, как я смог понять ищет новые устройства на шине (команда 0xf0), если находит то возвращает 1 и адрес устройства.
посчитать количество устройств можно так (взято из библиотеки DallasTemperature):
Скачайте библиотеку DallasTemperature
И далее получение температуры с конкретного датчика выглядит так:
tempS1 = sensors.getTempC(sensor_1);
tempS2 = sensors.getTempC(sensor_2);
tempS3 = sensors.getTempC(sensor_3);
где DeviceAddress sensor_1, sensor_2, sensor_3;
Схему подключения и пример как работает, можно тут посмотреть.
спасибо, кое что уже получилось с использованием данной библиотеки.
Простите за нубский вопрос. При использовании библиотеки DallasTemperature как нумеруются датчики? Самый ближний будет первый, дальше второй и т.д. Или надо как то самому привязывать номер датчика к индивидуальному 64 адресу датчика? Тогда как это лучше сделать физически. Подключать по одному и запоминать/записывать их адрес???
вот как раз укаждого датчика есть этот индивидуальный номер(адрес датчика) по которому эти датчики и сортируются. И самый ближний к ардуино (по расстоянию до ардуино) может оказаться самым последним по индивидуальному адресу. Если вы не планируете постоянно добавлять датчики, то необходимо сначала считать все адреса всех датчиков и запомнить их и уже при запросе температуры указывать в запросе адрес интересующего из датчиков.
Значит пишем простой скетч, который считывает адрес датчика. По очереди подключаем по одному датчики, читаем их адреса, как то их помечаем (???). Впаиваем так как нам надо в шину, прописываем в рабочем скетче какому дачику какой номер присвоить и только тогда наслаждаемся работой. Я правильно понял???
Муторненько получается. А датчиков будет более 20.
По очереди подключаем по одному датчики, читаем их адреса, как то их помечаем (???).
Зачем так сложно? :) Монтируем датчики, включаем в скетче опрос с выводом в сериал-консоль номера и температуры и по очереди греем датчик так, чтобы его данные отличались от соседних... Для 20 датчиков - 20 минут с подходом и отходом от каждого датчика.
Думал об этом.
По растащенным по помещениям датчикам, плюс вдруг какой на солнце, какойто в корпусе и тд , по очереди греть - некомильфо. Сделал функцию на кнопке, для установки и записи в эпром адресов датчиков начиная с первого с последовательным подключением по очереди.
Поделитесь! Плиззз! И желательно более детально!
я по мере сил и времени пытаюсь сделать чтото вроде кситала
Сигнализация + управление температурой в доме , плюс поставил себе задачу чтобы была возможность установить и прописать все датчики без использования монитора: 4 кнопки 7 диодов
Смысл в следующем
В сетапе:
В озу формируется структура для термометров аналогичная эпромовской Thermometer
на этапе инициализации также берется реальное количество воткнутых в систему датчиков сравнивается с записанными в эпром. если эпром пустой - индикация на диодах на каждый реально существующий датчик - мол нет записи в эпром
код буквально такой
в результате получается в озу получается структура заполненая из eprom, каждый рекорд определяется полем Valid
если 55ff то все отлично датчик есть
теперь в loop на кнопке ( ну в режиме супервизора естественно и прочее) есть функция
SetupSensors
у нее несколько задач, таких как установка лимитов температуры регулировки , номеров реле отвечающих за датчик и установка типов датчиков ( корпусной, статистический для отчета, управляющий и тд) но в том числе она пишет в эпром все новые датчики оторые при ней подключаются, поэтому начинается она так
тоесть она в начале требует отключить все датчики кроме корпусного
потом на его пишет в эпром
Последняя строка - количество записаных датчиков
Потом идет цикл, функция требует либо добавить датчик, либо нажать кнопку ESC
она достаточна громоздка, в связи с устаноками для датчиков лимитов температур и прочего но если интерес то кину.
смысл в том что в цикле опрашивается количество текущих датчиков и при добавлении нового в онлайне
определяется его адрес и в случае если такого нет в текущем рекорде структуры Thermometr ОЗУ( Он может быть гдето ниже в структуре, но раз он попался скажем вторым в этой функции) то структура Thermometr заполняется на один рекорд. и пишется в эпром
датчик становится с адресом и с номером рекорда структуры
пришлось это делать изза двух причин:
1) при добавлении нового датчика он просто не всегда становится последним
2) Не хотелось хардкодить адрес корпусного датчика - вдруг сгорит
Плюсы - после установки датчиков не надо знать об из адресах ничего , только в сетапе проверить их на соответствие епромовским записям.
У тебя есть только номер датчика и присущие ему свойства (корпусной,релейный, статистический и тд)
и дальше ты уже знаешь какой конкретно у тебя датчик за что отвечает
У кситала в корпусе стоит DHT11 , они этим не стали заморачиваться :)
Была мысль сделать как советует Andrey_Y_Ostanov , все было бы проще, но тогда нужен хотябы экран, или Уповать на то что ты сделал самый горячий датчик (Зажигалкой?) Летом датчик может нагрется до 60 на солнце.
А если не заморачиваться и каждый датчик прицепить на отдельный пин? (Заказал мегу, там пинов хватит, правда кабелей будет поболее). Или там тоже надо будет обращаться по адресу?
Десятки кабелей только затем что-бы не выяснять у кого какой адресс?
IMHO проще, все-таки, подключить их вначале по одному и бирочку какую-то, с адресами к ним привязать.
Можно даже не в кноечную систему, а звять дуину отдельную и к ней подключить/посмотреть. Сделать себе как-бы "тестер проверялку адреса".
Да и сами датчики можно изначально не припаивать, а какой-то разъем предусмотреть (тем более все-ко бывает, может потребуется замена в будущем). Вынул датчик, подключил его к "тестовому оборудованию" - посмотрел адресс.
Или можно "инвертировать". Вначале все подключить, получить полный список адресов, а потом отключать по одному и смотреть "какой адресс исчез".
Но есть и плюс. При замене датчика не надо менять прошивку. А кабеля у меня ну максимум 3м, а многие и того меньше.
Подскажите пожалуйста, как присвоить переменной то что выдает Serial.print(addr[i],HEX)?
Пробовал вот так:
У меня тоже подключено несколько датчиков, я хочу по адресу датчика распределять ответы...
addr[] это и есть переменная, а точнее массив переменных, почитайте массив (array).
Спасибо, я это читал...
Как создавать массив я знаю, я не пойму почему не получается присвоить переменной adress полученный массив, который выводится в COM порт.
Если не сложно подскажите синтаксис...
пробовал и вот так:
Потому что у вас address не является массивом это раз и два нельзя просто так присвоить массив массиву. Почему нельзя в один пустой стакан налить 8 стаканов воды?
И почему нельзя одной рукой разом перелить 8 стаканов с водой в 8 пустых стаканов?
Присвоить массив массиву можно например функцией memcpy(array_1, array_2, len).
Сравнивать массивы можно например функцией memcmp(array_1, array_2, len).
пробовал и вот так:
Ну наверное, потому что нужно понять что сами переменные не имеют "системы исчисления". Цифры в переменных (и элементах массива) хранятся как "абстрактные". Представте себе коробку с яблоками. В ней лежит сколько-то яблок. Когда вас просят на бумажке написать "сколько там яблок", то это уже ваше дело, как писателя, напишите вы десятчиной цифрой 4, римской IV или двоичной B100. Ни коробка, ни яблоки от этого не изменятся. Если вам скажут "положи в ту коробку столько же яблок сколько лежит в это" (это и есть присвоение переменной) - то "римскую IV" не будете туда ложить. Вы будете ложить яблоки :)
Так и тут - переменная "коробка". В которой лежит какое значение числа, но нет инфрмации о его "формате". Это для людей. Поэтому выражение вида (addr[i],HEX) - не имеет смысла.
А вот для print - уже имеет. Это как раз "писатель". Поэтому ему важно знать "в какой системе исчисления вывести эту переменную ЧЕЛОВЕКУ".
Но.... скорее все вы хотели вывести все значения массива addr, а не только последнее, поэтому вам нужно почитать {} (фигурные скобки) | Аппаратная платформа Arduino и Оператор For | Аппаратная платформа Arduino
и правильно добавить фигурные скобки. что-бы Serial.print-ты тоже выполнялись в цикле, а не после него. Что-бы вывели каждый элемент.
Оператор for и фигурные скобки знакомы :)
Я понял что при каждом цикле for строка дописывается в COM порту Serial.print(addr[i],HEX)... Отсюда я получаю в терминале (Addr:28190C040074). Хочу вот этот полученный ответ "28190C040074" присваивать переменной, чтобы переменная имела вид: adress = '28190C040074' Возможно как-то реализовать?
Либо может есть более простой путь решения задачи? нужно читать адрес датчика, и по условию совпадения записанного адреса датчика вписывать его значения температуры...
Либо может есть более простой путь решения задачи? нужно читать адрес датчика, и по условию совпадения записанного адреса датчика вписывать его значения температуры...
Оператор for и фигурные скобки знакомы :)
Ну либо плохо знакомы, либо.... вы ввели в заблуждение что такое у вас переменная adress? Это массив? Это одна цифра адреса?
Если это "одна цифра", то не имеет смысла Serial.print(adress), так как принт не умеет выводить массивы.
Если это "массив", то почему вы пытались делать adress=addr[i]? То есть получали элемент массива и пытались присвоить его массиву? Тогда уже нужно было address[i]=addr[i]. Каждый элемент копировать отдельно (либо как вам показал Максим, через memcpy копировать сразу весь массив, без всяких циклов). Вообщем явно, как советовали выше - еще раз почитать про массивы.
Вообщем
1. Вы не показали что такое adress
2. Из дальнешего кода следует что это "одна цифра адреса"
3. Из ваших слов следуют что это "адресс целиком", то есть "массив".
Так что:
a. Определитесь что же именно вам нужно
б. Все-таки еще раз перечитайте соотвествующие разделы документации, что-бы выражать кодом свою мысль, а не подбирать-угадывать "как заработает"
в. В коде показывайте и объявления переменных. Тип переменных является очень важной инфой. Влияющией и на то как компилятор будет собирать прошивку и на самоу логику исполнения прошивки (поэтому про типы - тоже желательно почитать, что-бы в будущем не "лепить на обум", скажем int, там где хватило-бы byte").
Я пробовал сделать так как Вы писали "Maksim" в 24 сообщении...
Но условие не сработало... Поэтому и пытаюсь решить другими путями...
Может я не верно прописал переменные? В терминале я получаю адреса датчиков в виде: 28190C040074 и 28564C04003A.
я создал переменные вот такие:
Но не работает...
Не работает, потому что вы что не так делаете.
>Но не работает...
А какая у вас длина (размер) address_1 и adress_2? И addr?
А сколько байт вы сравниваете функцией memcmp?
Функция memcmp - вглядываемся в третий параметр.
Кстати, да. У меня массивы в примерах какой длинны??? А у вас?
И с какого вдруг 64-битный номер датчика у вас поместился в 6-ти байтах???
Не работает, потому что вы что не так делаете.
Перевод: не предполагайте наличие телепатов. ваш монитор никто не видит. старайтесь описывать "как именно не работает" (можно еще добавлять и "что ожидали" - тут тоже не всегда очевидно).
Номер для начала по нормальному прочитайте
Прямо из монитора копируете его.
Ясна, вот скетч:
Вот логи из COM порта:
Хочу сделать чтобы в добавок выводилось Temperature №1 = 28.06 для датчика №1 с адресом 28190C040074
Приблизительно вот так:
Сейчас подключил один датчик, чтобы случайно не запутаться...
только номера поменяйте на те что прочтутся.
Спасибо Максим за пост #34.
Скопировал я адрес датчика, в логах появилась нужнаю строка! Отлично! Но не пойму почему в логе задублированы строка Temperature_1 = 27.81, хотя по коду она должна один раз прописаться при одном цикле...
В терминале я получаю адреса датчиков в виде: 28190C040074
Значит неправильно получаете :(
Поленились сделать разделители между цифрами. У вас пропали "лидирующе нули". Если код был "02 08 ...." у вас вывеслось "2 8...." (нули впереди числа не дописываются). А так как пробел межу цифрами вы не выводите, то вы увидиле "28". И все у вас "два байта" превратиль в один :(
Выводит:
Адрес надо обнулять иначе при отсутствии следующего адреса при поиске датчиков адрес остается прежним и условие выполняется повторно.
Спасибо Максим за пост #34.
Скопировал я адрес датчика, в логах появилась нужнаю строка! Отлично! Но не пойму почему в логе задублированы строка Temperature_1 = 27.81, хотя по коду она должна один раз прописаться при одном цикле...
Возможно еще оптому что руками перенабирали текст Максима. И очепятались. У него в годе строки "Temperature_1" - вообще нет.
Спасибо, с переводом адреса датчика в номральный вид разобрался...
Не пойму почему так происходит? то есть при выполнении простого условия выполняется два раза его содержание...
Выдает в логах:
Пробовал вставить delay, ничего не изменилось...
Код для поиска ошибок:
Опять "кусок кода", который показался вам важным... проблема-то может быть и ниже :) Что у вас там в print написанно во втором условии?
Для поиска ошибок подключил второй датчик, и странно то что по второму датчику дублирования нет...
Вот логи из COM порта:
Не пойму почему так происходит? то есть при выполнении простого условия выполняется два раза его содержание...
Увидел 39 пост. добавил в код эту строку....
Ничего не изменилось... Так и осталось дублирование Температуры 1, а температура 2 не дублируется...
А если так?
Попробуйте вот это
Вставить, между
Почти одновременно )
Спасибо большое за супер помощь leshak и maksim!
Получил ожидаемый результат!
У меня такой вопрос, я хочу сделать опрос по датчикам, а потом к примеру через время 5-10 секунд сделать следующий опрос. Но я никак не могу понять, в какую часть кода мне вписат ьвременную задержку для следующего опроса