bwn, если вы помните -эти строчки в начале топика я писал, стало быть немножко в курсе что за что отвечает :) Там засада в последовательности операций. Невозможно запрограмммировать разрядность не запрограммировав предварительно обе температуры. Поэтому в данном случаен (с закоментированными пердыдщими строками) 17 строка устанавливает верхнюю температуру аларма :) Поэтому я написал снять ВСЕ ремарки. А товарищ пренебрёг этим..
ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение
там так и написано.
Если раскоментирую все строки
ds.reset(); // сброс шины
ds.select(addr); //выставить адрес
ds.write(0x4E); // разрешение записать конфиг
ds.write(0x7F); // Th контроль температуры макс 128грд
ds.write(0xFF); //Tl контроль температуры мин -128грд
ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение
По датущиту погрешность 0.5°C а разрядность запилить можно 0.0625°C.
Для чего???? Толку 0 с такой погрешностью.
PS. dimax, разобрался с выводом в сериал, но помоему эффект нулевой последние разряды вообще не меняютя. СПС за совет,
По изменению разрядности, в данном случае обе строки идентичны (меняем 5 и 6 бит), но применяем какую то одну.
Погрешность и точность не одно и тоже. Погрешность величина всегда постоянная для конкретного экземпляра, любой измерительный прибор ее имеет. Для получения идентичных результатов каждый прибор проходит периодическую поверку, полученный результат отклонения учитывается при последующих измерениях. Требуемая точность зависит от задачи, для измерения уличной температуры достаточно целых градусов, комнатной - 0,5гр., в ректификаторе мне потребовалась вся шкала.
С сериалом, ищите ошибку, все должно выводиться правильно.
Диод заряжает конденсатор и не даёт ему разряжаться когда в линии проскакивают "нули".
Поэтому датчик превращается из двухпроводного в как-бы трёхпроводный.
Но по двум проводам.
Другая особенность DS18B20 - способность работать без внешнего питания.
Эта возможность предоставляется через подтягивающий резистор.
Высокий сигнал шины заряжает внутренний конденсатор (CPP), который питает прибор,
когда на шине низкий уровень .
Этот метод носит название « Паразитное питание ».
При этом максимальная измеряемая температура при этом + 100 °C.
Для расширения диапазона температур до + 125 °C необходимо использовать внешнее питание.
Вот попробовал сваять с проверками и прочим. Чтобы при работе с датчиком не было проблем "потери сигнала" от датчика. Как показала практика, если этого не делать, то на груглосуточно работающем девайсе, с проверкой раз в 3 минуты температуры - раз в месяц или реже но прилетает тревога -0,06С
Новый код работает, но думаю есть огрехи которые я не вижу. что можно в коде еще улучшить?
float getTemp() {int ii; ii = 0; label: //Serial.println(ci);
if (ii < 6) { // возвращает температуру с датчика
byte data[12]; // и останавливает программу на секунду
byte addr[8];
if ( !ds.search(addr)) {
Serial.println F("No more addresses.");
Serial.println(addr[8]);
ds.reset_search();
delay(250);
++ii; goto label;
}
if (OneWire::crc8(addr, 7) != addr[7]) { //проверка массива адреса на срц
Serial.println F("CRC is not valid!");
++ii; goto label;
}
ds.search(addr); //
ds.reset_search();
ds.reset();
ds.select(addr);
ds.write(0x44);
delay(1000); wdt_reset();
ds.reset();
ds.select(addr);
ds.write(0xBE);
for (int i = 0; i < 9; i++) data[i] = ds.read();
if (OneWire::crc8(data, 8) != data[8]) { // проверка црц считанной температуры.
Serial.println F("Data CRC is not valid!");
++ii; goto label;
}
int raw = (data[1] << 8) | data[0]; // Переводим в температуру
if (data[7] == 0x10) raw = (raw & 0xFFF0) + 12 - data[6];
return raw / 16.0;
}
}
Во-первых, мелкая ошибка - в описании массива DoorsWindows (строка 55) - вы берете размер по числу датчиков температуры, а не по числу датчиков окон.
А вот дальше более серьезно. Не думаю, что мысль засунуть опрос четырех датчиков температуры и двадцать ! опросов датчиков окон в один вектор прерывания - это здравая идея. А с учетом того, что прерывание ватчдога имеет один из высших приоритетов, подозреваю, что совместно с этим кодом ничего другого на МК уже исполнятся не сможет.
Критика приветствуется. Спасибо за мелкую ошибку. исправил. И да, согласен на счет прерывания. Но у меня система модульная, ничего другого данный мк, в общем то и не делает. Имеет смысл переложить просто на миллис. Остальное думаю может кого заинтересует. Имею ввиду проверка CRC и считывание PIO ds2406.
Подскажите какую библиотеку использовать. Нужно обращатся к датчикам по сирийному номеру , я так понимаю с начала сирийные номера нужно саписать в еепром микроконтролера (ESP8266) чтобы если из групы датчиков один отключить то остальные оставались на своих местах .
Подскажите какую библиотеку использовать. Нужно обращатся к датчикам по сирийному номеру , я так понимаю с начала сирийные номера нужно саписать в еепром микроконтролера (ESP8266) чтобы если из групы датчиков один отключить то остальные оставались на своих местах .
Если речь идет о датчиках DS на протоколе One Wire, то и библиотеку нужно OneWire.h, чтобы записать в EEPROM - библиотеку EEPROM.h. Адрес датчика занимает 8 байт. В программе желательно предусмотреть возможность считывания адреса датчика и записи ее в EEPROM. Про библиотеки почитайте в гугле.
Подскажите какую библиотеку использовать. Нужно обращатся к датчикам по сирийному номеру , я так понимаю с начала сирийные номера нужно саписать в еепром микроконтролера (ESP8266) чтобы если из групы датчиков один отключить то остальные оставались на своих местах .
а зачем для этого в еепром писать? ну отключите вы один, ничего особо и не изменится. Вот, например, можно так опрашивать далласы #24. Дополнительных библиотек не нужно, только Onewire.h
У датчиков OneWire нет номеров, у них есть идентификаторы, которые выжжены в них на заводе. Они не могут измениться от отключения или подключения доп. датчиков.
У датчиков OneWire нет номеров, у них есть идентификаторы, которые выжжены в них на заводе. Они не могут измениться от отключения или подключения доп. датчиков.
Я хотел сказать например у меня в програме какой то датчик меряет температуру чего то - это будет датчик скажем номер один итд., вот эти номера я имел ввиду. И при замене какого то датчика остальные оставались на своих местах.
Гарантированно неизменны только ID в термометрах. Вся остальная относительная нумерация и её валидность - на совести программиста. Если таковой задачи не стояло при создании ПО, то внутрипрограммные индексы могут перестать соответствовать идентификаторам (а следовательно - местам установки) термометров. Так же - для получения проблем достаточно просто изъять один и поставить другое устройство OneWire.
Друзья, а не кажется Вам, что данная тема не предназначена для обучения работы с далласами?
То olegkaras, предлагаю создать СВОЮ тему в песочнице и там задать все интересующие вопросы. ИМХО.
Если я отключу какойто датчик или заменю его другим то остальные датчки останутся под своими номерами как и до отключения или замены ?
полагаю вы имеете ввиду, что определённые адреса датчиков так и останутся привязаны к определённым переменным температуры? в любом случае, отключение или замена одного из датчиков никак не повлияет на привязанность адресов датчиков к переменным (по крайней мере в моем примере).
Гражданин начальник ругается, конечно, и скоро ссаными тряпками нас гонять будет, как алегира, но сошлюсь на datasheet: "Each DS18B20-PAR has a unique 64-bit identification code...". Там же написано, что "The match ROM command followed by a 64–bit ROM code sequence allows the bus master to address a specific" - отсюда и простонародный "адрес", как я понимаю.
Меняю в скетче 15 строку на паразитное питание с изменением в схеме, температура не измеряется.
Стандартный пример из библиотеки OneWare работает с паразитным питанием прекрасно.
Сделать на delay вместо millis не вариант, т.к. есть много кода, который должен в это время исполняться.
Помогите, пожалуйста, разобраться в причине.
Сильно не пинайте, начинающий я.
И еще: aruino pro ide уже можно использовать или он слишком сырой пока?
#include <OneWire.h>
OneWire ds(6); // На каком пине Создаем объект OneWire для шины 1-Wire, с помощью которого будет осуществляться работа с датчиком температуры
float temperature = 0; // Переменная для хранения значение температуры с датчика DS18B20
uint32_t LastTempUpdateTime = 0; // Переменная для хранения времени последнего считывания с датчика
const int TempUpdateTime = 1000; // Определяем периодичность проверок температуры. ПРОЦЕДУРА ПРОИСХОДИТ ДОЛЬШЕ ОСТАЛЬНЫХ, НА НЕЕ НЕОБХОДИМО ПРИМЕРНО 750 МС.
void setup(){
Serial.begin(9600);
}
void detectTemperature() {
byte data[2]; // Место для значения температуры
ds.reset(); // Начинаем взаимодействие со сброса всех предыдущих команд и параметров
ds.write(0xCC); // Даем датчику DS18b20 команду пропустить поиск по адресу. В нашем случае только одно устрйоство
ds.write(0x44, 1); // Даем датчику DS18b20 команду измерить температуру. Само значение температуры мы еще не получаем - датчик его положит во внутреннюю память
ds.reset(); // Теперь готовимся получить значение измеренной температуры
ds.write(0xCC);
ds.write(0xBE); // Просим передать нам значение регистров со значением температуры
data[0] = ds.read(); // Читаем младший байт значения температуры
data[1] = ds.read(); // А теперь старший
// Формируем итоговое значение: "склеиваем" значение, затем умножаем его на коэффициент, соответсвующий разрешающей способности (для 12 бит по умолчанию - это 0,0625)
temperature = round(((data[1] << 8) | data[0]) * 0.0625 * 10) / 10.0; // умножить на 10 и округлить для избавления от сотых, затем разделить на 10
}
void loop(){
if (millis() - LastTempUpdateTime > TempUpdateTime) // отсчитываем временной интервал для измерения температуры
{
LastTempUpdateTime = millis();
detectTemperature(); // Определяем температуру от датчика DS18b20
}
Serial.println(temperature); // Выводим полученное значение температуры
}
ну так у вас паразитное питание включается в строке 15 и практически мгновенно сразу выключается в 17. Этого недостаточно, так работать не будет.
это потому что вы запрос и чтение температуры делаете подряд.
Возьмите код Димакса из первого сообщения ветки - там запрос и чтение делается в два захода. Нужно в конце запроса на температуру включить паразитное питание, а в начале чтения значений - выключить.
Код чисто тест, меняю константу в сторону увеличения с 0.0625 на 0.0672. То есть с 25.00 подогнал к фактической 26.88 °C. Или я заблуждаюсь?
#include <Wire.h>
#include <OneWire.h>
OneWire ds(5);
float temperature = 0 ;
void setup() {
// put your setup code here, to run once:
Serial.begin(57600);
}
void loop() {
// put your main code here, to run repeatedly:
//----- Определяем температуру на датчике.
byte data[2]; // Место для значения температуры
ds.reset(); // Начинаем взаимодействие со сброса всех предыдущих команд и параметров
ds.write(0xCC); // Даем датчику DS18b20 команду пропустить поиск по адресу. В нашем случае только одно устрйоство
ds.write(0x44); // Даем датчику DS18b20 команду измерить температуру. Само значение температуры мы еще не получаем - датчик его положит во внутреннюю память
ds.reset(); // Теперь готовимся получить значение измеренной температуры
ds.write(0xCC);
ds.write(0xBE); // Просим передать нам значение регистров со значением температуры
data[0] = ds.read(); // Читаем младший байт значения температуры
data[1] = ds.read(); // А теперь старший
temperature = ((data[1] << 8) | data[0]) * 0.0672; //----- Определяем температуру на датчике и подгоняем температуру под эталонную (0.0672) < Так!.
Serial.println(temperature);
}
Кстати по датчикам, Левыми оказались только с гильзами!
Поддельный датчик не поддерживает 9,10-битное разрешение и не сохраняет значения в регистрах аварийных сигналов. Кроме того, у моего поддельного датчика одно и тоже время преобразования - 487 мс при всех режимах преобразования, обычному датчику требуется около ~ 750 мс при 12 бит.
#include <OneWire.h> OneWire ds(2); byte addr[8]={0x28,0xFF,0x8D,0xEF,0x8B,0x16,0x03,0xBB}; volatile int celsius; void setup(void) { Serial.begin(9600); pinMode (13,OUTPUT); WDTCSR=(1<<WDCE)|(1<<WDE); //установить биты WDCE WDE (что б разрешить запись в другие биты WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда // (55 страница <a href="<a href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf" rel="nofollow">http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf</a>" rel="nofollow">даташита</a>) // снять все ремарки если нужно поменять разрешение ds.reset(); // сброс шины ds.select(addr); //выставить адрес ds.write(0x4E); // разрешение записать конфиг // ds.write(0x7F); // Th контроль температуры макс 128грд // ds.write(0xFF); //Tl контроль температуры мин -128грд ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение //ds.write(0x3F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F тоже не работает } void loop(void) { Serial.print(" Temperature = "); Serial.println(celsius/16.0); } ISR (WDT_vect){ //вектор прерывания WD static boolean n=0; // флаг работы: запрос температуры или её чтение n=!n; if (n) {ds.reset(); // сброс шины ds.select(addr); // выбор адреса ds.write(0x44); // начать преобразование (без паразитного питания) } else {ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad (чтение регистров) celsius = ds.read() | (ds.read()<<8); //прочитаны 2 байта } }попробовал с адресом, не работает.
ds.write(0x3F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F тоже не работает
see_watson, если вы зашили в том виде, в котором сейчас скетч -то 17ой строчкой вы установили аларм -предел макс. температуры
see_watson, если вы зашили в том виде, в котором сейчас скетч -то 17ой строчкой вы установили аларм -предел макс. температуры
Отнюдь, 17-я как раз 12 бит разрешение.
see_watson, а что на монитор выводит?
bwn, если вы помните -эти строчки в начале топика я писал, стало быть немножко в курсе что за что отвечает :) Там засада в последовательности операций. Невозможно запрограмммировать разрядность не запрограммировав предварительно обе температуры. Поэтому в данном случаен (с закоментированными пердыдщими строками) 17 строка устанавливает верхнюю температуру аларма :) Поэтому я написал снять ВСЕ ремарки. А товарищ пренебрёг этим..
ОК, упустил.(((
Чет показалось, что одной строчкой менял, давно это было.)))
dimax и bwn, пробовал из примера dimax , пост 4 -
там так и написано.
Если раскоментирую все строки
и добавляю
вродебы сдвиги есть,
но в сериал выдает до сотых(25.78, 25.66 и тд итп)
see_watson, изучите внимаьтельно аргументы функции http://arduino.ru/Reference/Serial/Print
и добавляю
Откуда вы эту строку выкопали?
и добавляю
Откуда вы эту строку выкопали?
пост 177.
Закрадывается вопрос???
По датущиту погрешность 0.5°C а разрядность запилить можно 0.0625°C.
Для чего???? Толку 0 с такой погрешностью.
Тогда получается что поставил по умолчанию до десятых ( азм есть) и забыл .
PS. dimax, разобрался с выводом в сериал, но помоему эффект нулевой последние разряды вообще не меняютя. СПС за совет,
PS2
Плюнул, оствил до десятых с такой погрешностью.
По датущиту погрешность 0.5°C а разрядность запилить можно 0.0625°C.Для чего???? Толку 0 с такой погрешностью.
Иногда относительная точность важнее абсолютной. Например рассчитывать перспективы изменения температуры, оценивая тенденцию за более короткий период.
По датущиту погрешность 0.5°C а разрядность запилить можно 0.0625°C.
Для чего???? Толку 0 с такой погрешностью.
PS. dimax, разобрался с выводом в сериал, но помоему эффект нулевой последние разряды вообще не меняютя. СПС за совет,
По изменению разрядности, в данном случае обе строки идентичны (меняем 5 и 6 бит), но применяем какую то одну.
Погрешность и точность не одно и тоже. Погрешность величина всегда постоянная для конкретного экземпляра, любой измерительный прибор ее имеет. Для получения идентичных результатов каждый прибор проходит периодическую поверку, полученный результат отклонения учитывается при последующих измерениях. Требуемая точность зависит от задачи, для измерения уличной температуры достаточно целых градусов, комнатной - 0,5гр., в ректификаторе мне потребовалась вся шкала.
С сериалом, ищите ошибку, все должно выводиться правильно.
BWN СПАСИБО за объяснение , чё-то сглупил.
допилил вот так. вроде работает.
#include <OneWire.h> OneWire ds(2); byte addr[8]={0x28,0xFF,0x8D,0xEF,0x8B,0x16,0x03,0xBB}; volatile int celsius; void setup(void) { Serial.begin(9600); pinMode (13,OUTPUT); WDTCSR=(1<<WDCE)|(1<<WDE); //установить биты WDCE WDE (что б разрешить запись в другие биты WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда // (55 страница <a href="<a href="<a data-cke-saved-href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf" href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf" rel="nofollow">http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf</a>" rel="nofollow"><a data-cke-saved-href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf" href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf" rel="nofollow">http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf</a></a>" rel="nofollow">даташита</a>) // снять все ремарки если нужно поменять разрешение ds.reset(); // сброс шины ds.select(addr); //выставить адрес ds.write(0x4E); // разрешение записать конфиг ds.write(0x7F); // Th контроль температуры макс 128грд ds.write(0xFF); //Tl контроль температуры мин -128грд ds.write(0x7F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F } void loop(void) { Serial.print(" Temperature = "); Serial.println(celsius/16.0, 4); } ISR (WDT_vect){ //вектор прерывания WD static boolean n=0; // флаг работы: запрос температуры или её чтение n=!n; if (n) {ds.reset(); // сброс шины ds.select(addr); // выбор адреса ds.write(0x44); // начать преобразование (без паразитного питания) } else {ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad (чтение регистров) celsius = ds.read() | (ds.read()<<8); //прочитаны 2 байта } }Вы только строки 12-18 закомментируйте обратно, не надо при каждом запуске ROM скрести.
Попробовал применить, и кроме считывания температуры еще добавил, что нужно было, с контролем времени. Все работает, спасибо
По времени 1.5 и 3 миллисекунды. Ардуина в принципе ничем не занимается почти все время
*конденсатор желательно с низким ESR
а какую роль выполяет диод?? роль RC цепочки по питанию? иногда плюс и минус датчика можно спутать, датчик греется, в нем диод..
Диод заряжает конденсатор и не даёт ему разряжаться когда в линии проскакивают "нули".
Поэтому датчик превращается из двухпроводного в как-бы трёхпроводный.
Но по двум проводам.
ааа.. разве что так.. но стоит ли экономить на одном проводнике?
схема вверху какой практически дает результат по дальности?
Датчик рассчитан на работу по двухпроводной схеме с паразитным питанием.
Там внутри и конденсатор и диод есть.
Зачем городить схему? Упростить код?
Первое :
Другая особенность DS18B20 - способность работать без внешнего питания.
Эта возможность предоставляется через подтягивающий резистор.
Высокий сигнал шины заряжает внутренний конденсатор (CPP), который питает прибор,
когда на шине низкий уровень .
Этот метод носит название « Паразитное питание ».
При этом максимальная измеряемая температура при этом + 100 °C.
Для расширения диапазона температур до + 125 °C необходимо использовать внешнее питание.
Ну схему то все равно городить придется, если даташиту верить.
Вот попробовал сваять с проверками и прочим. Чтобы при работе с датчиком не было проблем "потери сигнала" от датчика. Как показала практика, если этого не делать, то на груглосуточно работающем девайсе, с проверкой раз в 3 минуты температуры - раз в месяц или реже но прилетает тревога -0,06С
Новый код работает, но думаю есть огрехи которые я не вижу. что можно в коде еще улучшить?
float getTemp() {int ii; ii = 0; label: //Serial.println(ci); if (ii < 6) { // возвращает температуру с датчика byte data[12]; // и останавливает программу на секунду byte addr[8]; if ( !ds.search(addr)) { Serial.println F("No more addresses."); Serial.println(addr[8]); ds.reset_search(); delay(250); ++ii; goto label; } if (OneWire::crc8(addr, 7) != addr[7]) { //проверка массива адреса на срц Serial.println F("CRC is not valid!"); ++ii; goto label; } ds.search(addr); // ds.reset_search(); ds.reset(); ds.select(addr); ds.write(0x44); delay(1000); wdt_reset(); ds.reset(); ds.select(addr); ds.write(0xBE); for (int i = 0; i < 9; i++) data[i] = ds.read(); if (OneWire::crc8(data, 8) != data[8]) { // проверка црц считанной температуры. Serial.println F("Data CRC is not valid!"); ++ii; goto label; } int raw = (data[1] << 8) | data[0]; // Переводим в температуру if (data[7] == 0x10) raw = (raw & 0xFFF0) + 12 - data[6]; return raw / 16.0; } }Тоже сделал проверку контрольной суммы, а то изредка , но бывают глюки показаний.
так как датчиков много переменные и адреса датчиков сделал в массивы, иначе код большой получается.
Также у меня используются датчики открытия дверей и окон на основе DS2406 и герконов. Написал код совместной работы с DS18B20.
За основу взят код автора темы.
#include <OneWire.h> OneWire ds(2); // выбор пина ардуино, на котором висит шина 1-wire // ниже перечисление температур typedef enum Temper_enum { KuhnyaC, //0 VannaNizC, //1 FreezeC, //2 UlicaC, //3 size_array_Temp //4 size } Temper_ENUM; // ниже соответствие адресов датчиков определённым температурам byte ADDR_DS18B20 [size_array_Temp][8] = { {0x28, 0xFF, 0xB1, 0x43, 0x52, 0x15, 0x01, 0xDB}, //KuhnyaC 0 {0x28, 0xFF, 0xBA, 0x6C, 0x52, 0x15, 0x01, 0x41}, //VannaNizC 1 {0x28, 0xEE, 0x9B, 0x4D, 0x25, 0x16, 0x02, 0xC5}, //FreezeC 2 {0x28, 0x9D, 0xE5, 0x70, 0x01, 0x00, 0x00, 0xEE} //UlicaC 3 }; // ниже сами переменные температур, изначально ставим +20*С volatile int8_t Temper[size_array_Temp] = { 20, //KuhnyaC 0 20, //VannaNizC 1 20, //FreezeC 2 20 //UlicaC 3 }; // например, чтобы использовать переменную температуры на улице, пишем так: Temper[UlicaC] = // ниже перечисление булевых значений для датчиков на основе ds2406 typedef enum Windows_enum { Window1Prihozh, //0 Window2Prihozh, //1 Window1Zal, //2 Window2Zal, //3 size_array_Windows //4 size } Windows_ENUM; // ниже сами булевые переменные окон, по умолчанию ставим, что все закрыты ("1"); volatile bool DoorsWindows[size_array_Windows] = { 1, //Window1Prihozh 1, //Window2Prihozh 1, //Window1Zal 1 //Window2Zal }; //адреса датчиков ds2406 byte ADDR_DS2406[size_array_Windows][8] = { {0x12, 0xA1, 0xEE, 0x47, 0x00, 0x00, 0x00, 0x58}, //Window1Prihozh {0x12, 0xA1, 0x43, 0x5C, 0x00, 0x00, 0x00, 0x58}, //Window2Prihozh {0x12, 0xA1, 0xEE, 0x5C, 0x00, 0x00, 0x04, 0x58}, //Window1Zal {0x12, 0xA1, 0xEE, 0x5C, 0x00, 0x00, 0x00, 0x58} //Window2Zal }; void setup() { //ниже настройки прерывания вочдог в котором будет опрашиваться шина 1-wire WDTCSR=(1<<WDCE)|(1<<WDE); // для таймера вочдог, на котором висит измерение для датчиков шины 1-wire WDTCSR=(1<<WDIE)|(1<<WDP2)|(1<<WDP1); // обновление шины 1-wire раз в 1 сек (2 сек для датчиков t, т.к. через раз) //WDTCSR=(1<<WDIE)|(1<<WDP3)|(1<<WDP1); // обновление шины 1-wire раз в 4 сек (8 сек для датчиков t, т.к. через раз) //WDTCSR=(1<<WDIE)|(1<<WDP3)|(1<<WDP0); // обновление шины 1-wire раз в 8 сек (16 сек для датчиков t, т.к. через раз) } void loop() { } ISR (WDT_vect){ //вектор прерывания WD . Здесь происходит опрос датчиков шины 1-Wire static boolean n=0; // флаг работы: запрос температуры или её чтение n=!n; if (n) {ds.reset(); // сброс шины ds.write(0xCC);//обращение ко всем датчикам ds.write(0x44);// начать преобразование (без паразитного питания) } else { for (byte i = 0; i < size_array_Temp; i++){// цикл фор перебирает все датчики t int Temper_= 20; byte buff[9]; ds.reset(); ds.select(ADDR_DS18B20[i]); //выбор адреса DS18B20 ds.write(0xBE); // Read Scratchpad (чтение регистров) for (byte j = 0; j<9; j++) buff[j]= ds.read(); //читаем все 9 байт от датчика ds.reset(); if (OneWire::crc8(buff, 8) == buff[8]){ // если CRC верна Temper_ = buff[0] | (buff[1]<<8); // читаем температуру из первых двух байт (остальные были нужны для проверки CRC) Temper_ = Temper_ / 16; if (Temper_ < 150 && Temper_ > -50 && Temper_ !=85 && Temper_!=-127) // ещё раз перестраховываемся от дерьмовых значений { Temper[i] = (int8_t) Temper_; // всё, тут уже пишем температуру в переменную } } } } for (byte h = 0; h<size_array_Windows; h++ ){// этот цикл фор перебирает все адреса ds2406 byte counteR = 0; for (byte p = 0; p<5; p++){ // этот цикл фор делает 5 измерений для каждой переменной для надёжности byte buf[7]; ds.reset(); ds.select(ADDR_DS2406[h]); // выбор адреса ds2406 buf[0] = 0xF5; // байты buf[1] = 0x45; // запроса buf[2] = 0xFF; // на 2406 ds.write_bytes(buf, 3); ds.read_bytes(buf+3, 4); // 3 cmd bytes, 1 data byte, 1 0x00, 2 CRC16 ds.reset(); if (OneWire::check_crc16(buf, 5, &buf[5])) { //если контрольная сумма верна - измеряем if (bitRead(buf[3], 2)) {DoorsWindows[h] = 1; break; } else counteR++; } } if (counteR == 5) DoorsWindows[h] = 0; // если все 5 раз было 0, то переменную делаем 0. } }MaksVV - критика принимается?
Во-первых, мелкая ошибка - в описании массива DoorsWindows (строка 55) - вы берете размер по числу датчиков температуры, а не по числу датчиков окон.
А вот дальше более серьезно. Не думаю, что мысль засунуть опрос четырех датчиков температуры и двадцать ! опросов датчиков окон в один вектор прерывания - это здравая идея. А с учетом того, что прерывание ватчдога имеет один из высших приоритетов, подозреваю, что совместно с этим кодом ничего другого на МК уже исполнятся не сможет.
Критика приветствуется. Спасибо за мелкую ошибку. исправил. И да, согласен на счет прерывания. Но у меня система модульная, ничего другого данный мк, в общем то и не делает. Имеет смысл переложить просто на миллис. Остальное думаю может кого заинтересует. Имею ввиду проверка CRC и считывание PIO ds2406.
пример на миллис
#include <OneWire.h> OneWire ds(2); // выбор пина ардуино, на котором висит шина 1-wire // ниже перечисление температур typedef enum Temper_enum { KuhnyaC, //0 VannaNizC, //1 FreezeC, //2 UlicaC, //3 size_array_Temp //4 size } Temper_ENUM; // ниже соответствие адресов датчиков определённым температурам byte ADDR_DS18B20 [size_array_Temp][8] = { {0x28, 0xFF, 0xB1, 0x43, 0x52, 0x15, 0x01, 0xDB}, //KuhnyaC 0 {0x28, 0xFF, 0xBA, 0x6C, 0x52, 0x15, 0x01, 0x41}, //VannaNizC 1 {0x28, 0xEE, 0x9B, 0x4D, 0x25, 0x16, 0x02, 0xC5}, //FreezeC 2 {0x28, 0x9D, 0xE5, 0x70, 0x01, 0x00, 0x00, 0xEE} //UlicaC 3 }; // ниже сами переменные температур, изначально ставим +20*С int8_t Temper[size_array_Temp] = { 20, //KuhnyaC 0 20, //VannaNizC 1 20, //FreezeC 2 20 //UlicaC 3 }; // например, чтобы использовать переменную температуры на улице, пишем так: Temper[UlicaC] = // ниже перечисление булевых значений для датчиков на основе ds2406 typedef enum Windows_enum { Window1Prihozh, //0 Window2Prihozh, //1 Window1Zal, //2 Window2Zal, //3 size_array_Windows //4 size } Windows_ENUM; // ниже сами булевые переменные окон, по умолчанию ставим, что все закрыты ("1"); bool DoorsWindows[size_array_Windows] = { 1, //Window1Prihozh 1, //Window2Prihozh 1, //Window1Zal 1 //Window2Zal }; //адреса датчиков ds2406 byte ADDR_DS2406[size_array_Windows][8] = { {0x12, 0xA1, 0xEE, 0x47, 0x00, 0x00, 0x00, 0x58}, //Window1Prihozh {0x12, 0xA1, 0x43, 0x5C, 0x00, 0x00, 0x00, 0x58}, //Window2Prihozh {0x12, 0xA1, 0xEE, 0x5C, 0x00, 0x00, 0x04, 0x58}, //Window1Zal {0x12, 0xA1, 0xEE, 0x5C, 0x00, 0x00, 0x00, 0x58} //Window2Zal }; uint32_t prev1Wire_polling = 0; byte interval_1wire = 4; // интервал опроса шины 1-wire, сек. (для датчиков t умножить на 2) boolean n=0; void setup() { Serial.begin(9600); } void loop() { if (millis() - prev1Wire_polling > (uint32_t)interval_1wire*1000){ // Здесь происходит опрос датчиков шины 1-Wire // флаг работы: запрос температуры или её чтение n=!n; if (n) {ds.reset(); // сброс шины ds.write(0xCC);//обращение ко всем датчикам ds.write(0x44);// начать преобразование (без паразитного питания) } else { for (byte i = 0; i < size_array_Temp; i++){// цикл фор перебирает все датчики t int Temper_= 20; byte buff[9]; ds.reset(); ds.select(ADDR_DS18B20[i]); //выбор адреса DS18B20 ds.write(0xBE); // Read Scratchpad (чтение регистров) for (byte j = 0; j<9; j++) buff[j]= ds.read(); //читаем все 9 байт от датчика ds.reset(); if (OneWire::crc8(buff, 8) == buff[8]){ // если CRC верна Temper_ = buff[0] | (buff[1]<<8); // читаем температуру из первых двух байт (остальные были нужны для проверки CRC) Temper_ = Temper_ / 16; if (Temper_ < 150 && Temper_ > -50 && Temper_ !=85 && Temper_!=-127) // ещё раз перестраховываемся от дерьмовых значений { Temper[i] = (int8_t) Temper_; // всё, тут уже пишем температуру в переменную } } } } for (byte h = 0; h<size_array_Windows; h++ ){// этот цикл фор перебирает все адреса ds2406 byte counteR = 0; for (byte p = 0; p<5; p++){ // этот цикл фор делает 5 измерений для каждой переменной для надёжности byte buf[7]; ds.reset(); ds.select(ADDR_DS2406[h]); // выбор адреса ds2406 buf[0] = 0xF5; // байты buf[1] = 0x45; // запроса buf[2] = 0xFF; // на 2406 ds.write_bytes(buf, 3); ds.read_bytes(buf+3, 4); // 3 cmd bytes, 1 data byte, 1 0x00, 2 CRC16 ds.reset(); if (OneWire::check_crc16(buf, 5, &buf[5])) { //если контрольная сумма верна - измеряем if (bitRead(buf[3], 2)) {DoorsWindows[h] = 1; break; } else counteR++; } } if (counteR == 5) DoorsWindows[h] = 0; // если все 5 раз было 0, то переменную делаем 0. } Serial.print ("Temper AntiFreeze = "); Serial.println (Temper[FreezeC]); Serial.print ("Window2Zal = "); Serial.println (DoorsWindows[Window2Zal]); prev1Wire_polling = millis(); } }Подскажите какую библиотеку использовать. Нужно обращатся к датчикам по сирийному номеру , я так понимаю с начала сирийные номера нужно саписать в еепром микроконтролера (ESP8266) чтобы если из групы датчиков один отключить то остальные оставались на своих местах .
Подскажите какую библиотеку использовать. Нужно обращатся к датчикам по сирийному номеру , я так понимаю с начала сирийные номера нужно саписать в еепром микроконтролера (ESP8266) чтобы если из групы датчиков один отключить то остальные оставались на своих местах .
Если речь идет о датчиках DS на протоколе One Wire, то и библиотеку нужно OneWire.h, чтобы записать в EEPROM - библиотеку EEPROM.h. Адрес датчика занимает 8 байт. В программе желательно предусмотреть возможность считывания адреса датчика и записи ее в EEPROM. Про библиотеки почитайте в гугле.
Подскажите какую библиотеку использовать. Нужно обращатся к датчикам по сирийному номеру , я так понимаю с начала сирийные номера нужно саписать в еепром микроконтролера (ESP8266) чтобы если из групы датчиков один отключить то остальные оставались на своих местах .
а зачем для этого в еепром писать? ну отключите вы один, ничего особо и не изменится. Вот, например, можно так опрашивать далласы #24. Дополнительных библиотек не нужно, только Onewire.h
Если я отключу какойто датчик или заменю его другим то остальные датчки останутся под своими номерами как и до отключения или замены ?
У датчиков OneWire нет номеров, у них есть идентификаторы, которые выжжены в них на заводе. Они не могут измениться от отключения или подключения доп. датчиков.
да
У датчиков OneWire нет номеров, у них есть идентификаторы, которые выжжены в них на заводе. Они не могут измениться от отключения или подключения доп. датчиков.
Я хотел сказать например у меня в програме какой то датчик меряет температуру чего то - это будет датчик скажем номер один итд., вот эти номера я имел ввиду. И при замене какого то датчика остальные оставались на своих местах.
Да, забыл, если какой то татчик сломался или его отключили в этом примере есть вывод аварии датчика через терминал?
Гарантированно неизменны только ID в термометрах. Вся остальная относительная нумерация и её валидность - на совести программиста. Если таковой задачи не стояло при создании ПО, то внутрипрограммные индексы могут перестать соответствовать идентификаторам (а следовательно - местам установки) термометров. Так же - для получения проблем достаточно просто изъять один и поставить другое устройство OneWire.
Друзья, а не кажется Вам, что данная тема не предназначена для обучения работы с далласами?
То olegkaras, предлагаю создать СВОЮ тему в песочнице и там задать все интересующие вопросы. ИМХО.
полагаю вы имеете ввиду, что определённые адреса датчиков так и останутся привязаны к определённым переменным температуры? в любом случае, отключение или замена одного из датчиков никак не повлияет на привязанность адресов датчиков к переменным (по крайней мере в моем примере).
номер, адрес, индентификатор .... все нормальные разборки начинаются с однозначных опредлений понятий.
А то помню, как мы с дружком раз играли в шахматы в слепую, и как потом оказалось, оба белыми
Гражданин начальник ругается, конечно, и скоро ссаными тряпками нас гонять будет, как алегира, но сошлюсь на datasheet: "Each DS18B20-PAR has a unique 64-bit identification code...". Там же написано, что "The match ROM command followed by a 64–bit ROM code sequence allows the bus master to address a specific" - отсюда и простонародный "адрес", как я понимаю.
Гражданин начальник ругается, конечно, и скоро ссаными тряпками нас гонять будет, как алегира,
Неа, здесь dimax главный, ему решать.
Здравствуйте!
Меняю в скетче 15 строку на паразитное питание с изменением в схеме, температура не измеряется.
Стандартный пример из библиотеки OneWare работает с паразитным питанием прекрасно.
Сделать на delay вместо millis не вариант, т.к. есть много кода, который должен в это время исполняться.
Помогите, пожалуйста, разобраться в причине.
Сильно не пинайте, начинающий я.
И еще: aruino pro ide уже можно использовать или он слишком сырой пока?
#include <OneWire.h> OneWire ds(6); // На каком пине Создаем объект OneWire для шины 1-Wire, с помощью которого будет осуществляться работа с датчиком температуры float temperature = 0; // Переменная для хранения значение температуры с датчика DS18B20 uint32_t LastTempUpdateTime = 0; // Переменная для хранения времени последнего считывания с датчика const int TempUpdateTime = 1000; // Определяем периодичность проверок температуры. ПРОЦЕДУРА ПРОИСХОДИТ ДОЛЬШЕ ОСТАЛЬНЫХ, НА НЕЕ НЕОБХОДИМО ПРИМЕРНО 750 МС. void setup(){ Serial.begin(9600); } void detectTemperature() { byte data[2]; // Место для значения температуры ds.reset(); // Начинаем взаимодействие со сброса всех предыдущих команд и параметров ds.write(0xCC); // Даем датчику DS18b20 команду пропустить поиск по адресу. В нашем случае только одно устрйоство ds.write(0x44, 1); // Даем датчику DS18b20 команду измерить температуру. Само значение температуры мы еще не получаем - датчик его положит во внутреннюю память ds.reset(); // Теперь готовимся получить значение измеренной температуры ds.write(0xCC); ds.write(0xBE); // Просим передать нам значение регистров со значением температуры data[0] = ds.read(); // Читаем младший байт значения температуры data[1] = ds.read(); // А теперь старший // Формируем итоговое значение: "склеиваем" значение, затем умножаем его на коэффициент, соответсвующий разрешающей способности (для 12 бит по умолчанию - это 0,0625) temperature = round(((data[1] << 8) | data[0]) * 0.0625 * 10) / 10.0; // умножить на 10 и округлить для избавления от сотых, затем разделить на 10 } void loop(){ if (millis() - LastTempUpdateTime > TempUpdateTime) // отсчитываем временной интервал для измерения температуры { LastTempUpdateTime = millis(); detectTemperature(); // Определяем температуру от датчика DS18b20 } Serial.println(temperature); // Выводим полученное значение температуры }Меняю в скетче 15 строку на паразитное питание с изменением в схеме, температура не измеряется.
И что вы изменили? Единичку после 0х44 поставили. что ли?
Меняю в скетче 15 строку на паразитное питание с изменением в схеме, температура не измеряется.
И что вы изменили? Единичку после 0х44 поставили. что ли?
да
ну так у вас паразитное питание включается в строке 15 и практически мгновенно сразу выключается в 17. Этого недостаточно, так работать не будет.
это потому что вы запрос и чтение температуры делаете подряд.
Возьмите код Димакса из первого сообщения ветки - там запрос и чтение делается в два захода. Нужно в конце запроса на температуру включить паразитное питание, а в начале чтения значений - выключить.
ну так у вас паразитное питание включается в строке 15 и практически мгновенно сразу выключается в 17. Этого недостаточно, так работать не будет.
это потому что вы запрос и чтение температуры делаете подряд.
Спасибо! Помогли разобраться.
Всем привет.
Пришли три разные партии датчиков (c гильзой и без, все с али) все с ядром С4.
Решил проверить их на погрешность при 25 *С и мал мал офигел от результата, все врут в минус от 0,6 до 1,3 *С, китай однако отжигает в 2020.
Вопрос:
Можно влезть в 12 битный режим и поправить там переменную 0,0625 не добавляя к результату константу коррекции?
Или есть биты для коррекции датчика в + или -?
Чем черевато сие вмешательство? Проверил, меняя переменную можно подогнать РЛО к реальной температуре!
Как подгоняете?
Код чисто тест, меняю константу в сторону увеличения с 0.0625 на 0.0672. То есть с 25.00 подогнал к фактической 26.88 °C. Или я заблуждаюсь?
#include <Wire.h> #include <OneWire.h> OneWire ds(5); float temperature = 0 ; void setup() { // put your setup code here, to run once: Serial.begin(57600); } void loop() { // put your main code here, to run repeatedly: //----- Определяем температуру на датчике. byte data[2]; // Место для значения температуры ds.reset(); // Начинаем взаимодействие со сброса всех предыдущих команд и параметров ds.write(0xCC); // Даем датчику DS18b20 команду пропустить поиск по адресу. В нашем случае только одно устрйоство ds.write(0x44); // Даем датчику DS18b20 команду измерить температуру. Само значение температуры мы еще не получаем - датчик его положит во внутреннюю память ds.reset(); // Теперь готовимся получить значение измеренной температуры ds.write(0xCC); ds.write(0xBE); // Просим передать нам значение регистров со значением температуры data[0] = ds.read(); // Читаем младший байт значения температуры data[1] = ds.read(); // А теперь старший temperature = ((data[1] << 8) | data[0]) * 0.0672; //----- Определяем температуру на датчике и подгоняем температуру под эталонную (0.0672) < Так!. Serial.println(temperature); }Кстати по датчикам, Левыми оказались только с гильзами!
Поддельный датчик не поддерживает 9,10-битное разрешение и не сохраняет значения в регистрах аварийных сигналов. Кроме того, у моего поддельного датчика одно и тоже время преобразования - 487 мс при всех режимах преобразования, обычному датчику требуется около ~ 750 мс при 12 бит.
Тестировал по данной методе, вернее кодом) - https://github.com/Deimos1994/Ds_Fake_Tester
Мой мод :)
#include <Wire.h> #include <OneWire.h> #include <DallasTemperature.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define ONE_WIRE_BUS 5 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); uint8_t deviceCount = 0; const uint8_t PARASITE = 0; uint8_t highAlarmValue = 25; uint8_t lowAlarmValue = 10; uint32_t timeCon = 0; uint8_t resol = 12; uint32_t millChngRes = 0; void setup() { Serial.begin(9600); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64 Serial.println(F("SSD1306 allocation failed")); for (;;); // Don't proceed, loop forever } // Clear the buffer display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); display.print(F("DS18B20")); display.setCursor(0, 20); display.print(F("FakeFinder v2.0")); display.setCursor(0, 30 ); display.print(F("mod by iStarCom 2020")); display.setCursor(0, 40 ); display.print(F("add Address print.")); display.setCursor(0, 50 ); display.print(F("no data Serial print.")); display.display(); delay(5000); } void loop() { if (resol == 13) { resol = 9; } sensors.begin(); //deviceCount = sensors.getDS18Count(); deviceCount = sensors.getDeviceCount(); display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); display.println("Dev.#: " + String(deviceCount)); display.setCursor(0, 9); display.println("Addr: " + String(Address_r())); display.setCursor(0, 17); display.println(SetResolution(resol)); delay(50); uint32_t startMillis = millis(); sensors.requestTemperatures(); // Request temperature mesurments timeCon = millis() - startMillis; // calculate time delay(50); display.setCursor(0, 27); display.println("SET alarm: " + method2()); display.setCursor(0, 37); display.println("GOT alarm: " + readDevicesMethod2()); display.setCursor(0, 47); display.println("TEMP: " + String(sensors.getTempCByIndex(0)) + " C"); display.setCursor(0, 57); display.println("TimeCon: " + String(timeCon) + " ms"); display.display(); delay(50); // change resolution every xx sec if (millis() > millChngRes + 5000 && millis() > 12000) { resol++; millChngRes = millis(); } } //================================================ String method2() { // using direct OneWire write commands String msg; highAlarmValue++; lowAlarmValue++; oneWire.reset_search(); uint8_t addr[8]; while (oneWire.search(addr)) { if (OneWire::crc8(addr, 7) == addr[7]) { oneWire.reset(); oneWire.select(addr); oneWire.write(0x4E); // Write to scratchpad oneWire.write(highAlarmValue); // Write high alarm value oneWire.write(lowAlarmValue); // Write low alarm value oneWire.write(0x7F); // Write configuration register, 12 bit temp res delay(30); // dallas temp lib doesn't delay oneWire.reset(); oneWire.select(addr); oneWire.write(0x48, PARASITE); //copy scratchpad to eeprom, 1 - parasite power delay(20); // need at least 10ms eeprom write delay if (PARASITE) delay(10); msg = String(highAlarmValue) + " / " + String(lowAlarmValue); } else { msg = "Bad device addr!"; } } return msg; } //================================================ String readDevicesMethod2() { // using direct OneWire write commands uint8_t hAlarmValue; uint8_t lAlarmValue; uint8_t addr[8]; uint8_t data[9]; String msg; oneWire.reset_search(); while (oneWire.search(addr)) { if (OneWire::crc8(addr, 7) == addr[7]) { oneWire.reset(); oneWire.select(addr); oneWire.write(0xB8); // Copy eeprom to scratchpad cmd, missing from DallasTemperature library delay(50); oneWire.reset(); oneWire.select(addr); oneWire.write(0xBE); // Read scratchpad cmd delay(50); for (uint8_t i = 0; i < 9; i++) { data[i] = 0; data[i] = oneWire.read(); } hAlarmValue = data[2]; // byte 2 is high temp alarm lAlarmValue = data[3]; // byte 3 is low temp alarm msg = String(hAlarmValue) + " / " + String(lAlarmValue); } else { msg = "Bad device addr!"; } } return msg; } //================================================ // Loop through each device, print out address String SetResolution(uint8_t resSet) { String msg; for (int i = 0; i < deviceCount; i++) { // Search the wire for address if (sensors.getAddress(tempDeviceAddress, i)) { // set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions) sensors.setResolution(tempDeviceAddress, resSet); msg += "SetTo/Real: "; msg += String(resSet, DEC); msg += " / "; msg += String(sensors.getResolution(tempDeviceAddress), DEC); } else { msg = "Err."; } } return msg; } //================================================ String Address_r() { String msg; for (int i = 0; i < deviceCount; i++) { // Search the wire for address if (sensors.getAddress(tempDeviceAddress, i)) { for (uint8_t i = 0; i < 8; i++) { msg += String(tempDeviceAddress[i], HEX); } } else { msg = "Err."; } } return msg; } //================================================Что скажете?