Всем привет. Все, наверняка, знают цифровые термодатчики DS18B20. Вот и я решил с ними познакомится поближе. Купил - подключил - работают. НО... Никак в толк не возьму, либо я что-то упускаю из вида в работе с ними, либо действительно проблема в датчиках. Суть - решил использовать эти датчики в своем проекте, на ряду с такими компонентами, как LCD (I2C), ИК-приемник и многое, многое другое, но остановимся на этом. Датчики - 2 шт., используемая библиотека <DallasTemperature.h>. Так вот, при опросе датчиков и вывода значений на экран, Arduino "тормозит" и очень заметно, соответственно все остальные процессы (в скетче) тоже работают с задержкой: команды с ИК-пульта доходят через раз и все, что управляется с пульта, разумеется, работает раз через раз и т.д. Я понимаю, что датчики цифровые и нужно время, чтобы их опросить, но все же - это особенность библиотеки или все ресурсы Arduino Uno тратятся на снятия показаний с датчиков? Скетч: PHP: #include <IRremote.h> // IR #include <Wire.h> // I2C #include <LiquidCrystal_I2C.h> // LCD #include <OneWire.h> // DS18b20 #include <DallasTemperature.h> #define RELAY_PIN 9 #define RELAY_PIN2 10 #define RELAY_PIN3 11 #define IR_PIN 5 // DS18b20 #define ONE_WIRE_BUS 4 LiquidCrystal_I2C lcd(0x27, 20, 4); #define LCD_UPDATE_TIME 250 unsigned long lcdLastUpdateTime = 0; IRrecv irrecv(IR_PIN); decode_results results; // Реле bool LampState = false; bool LampState2 = false; bool LampState3 = false; //DS18b20 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress sensor1 = {0x28, 0xFF, 0xF2, 0x9C, 0x67, 0x14, 0x04, 0xF7}; // адреса датчиков DeviceAddress sensor2 = {0x28, 0xFF, 0xA1, 0x9B, 0x67, 0x14, 0x04, 0xAA}; // Температура float temp1; // текущая температура первого датчика float temp2; // второй датчик void setup() { Wire.begin(); lcd.init(); lcd.backlight(); // вкл. подсветку LCD (noBack-выкл) lcd.clear(); sensors.begin(); sensors.setResolution(sensor1, 10); sensors.setResolution(sensor2, 10); pinMode(IR_PIN, INPUT); pinMode(RELAY_PIN, OUTPUT); pinMode(RELAY_PIN2, OUTPUT); pinMode(RELAY_PIN3, OUTPUT); digitalWrite(RELAY_PIN, LOW); digitalWrite(RELAY_PIN2, LOW); digitalWrite(RELAY_PIN3, LOW); irrecv.enableIRIn(); // Включаем ресивер } void loop() { // Реле if (irrecv.decode(&results)) { if (results.value == 524543) LampState = !LampState; if (LampState) { digitalWrite(RELAY_PIN, HIGH); } else { digitalWrite(RELAY_PIN, LOW); } if (results.value == 573503) LampState2 = !LampState2; if (LampState2) { digitalWrite(RELAY_PIN2, HIGH); } else { digitalWrite(RELAY_PIN2, LOW); } if (results.value == 532703) LampState3 = !LampState3; if (LampState3) { digitalWrite(RELAY_PIN3, HIGH); } else { digitalWrite(RELAY_PIN3, LOW); } irrecv.resume(); // Получаем следующее значение } if (millis() - lcdLastUpdateTime > LCD_UPDATE_TIME) // обращаемся к датчикам раз в 250 мс { lcdLastUpdateTime = millis(); // отображение на LCD printTemperature(sensor1); // опрашиваем датчики printTemperature(sensor2); } } void printTemperature(DeviceAddress deviceAddress) // DS18B20 { sensors.requestTemperatures(); // Температура temp1 = sensors.getTempC(sensor1); // получаем температуру lcd.setCursor(11, 0); lcd.print("T1: "); lcd.print(temp1, 1); // отображение температуры lcd.print("C "); lcd.print(" "); temp2 = sensors.getTempC(sensor2); lcd.setCursor(11, 1); lcd.print("T2: "); lcd.print(temp2, 1); // отображение температуры lcd.print("C"); lcd.print(" "); } Если закомментировать строчки: Код (Text): printTemperature(sensor1); // опрашиваем датчики printTemperature(sensor2); то скетч выполняется как надо, без всяких задержек. Если только одну, то скетч выполняется с менее сильными задержками, но они все равно очень сильно портят общение с Arduino Можно как-то оптимизировать затрачиваемые ресурсы Arduino, чтобы ей хватало времени на работу с другими устройствами? Спасибо.
это ваша проблемка обсуждается -- задержки в библиотеке http://arduino.ru/forum/programmirovanie/ubrat-delay-iz-biblioteki-ds18b20
это особенность этих датчиков - им надо 0,7 сек на обработку данных. Используемая вами библиотека это время просто тупо ждет. Выход - обращаться к датчику два раза: первый раз - дать ему команду на измерение и обработку данных, но не ждать ответа; второй раз - через 1 сек (можно использовать скетч Blink without delay для отсчета времени без задержки) и забрать готовые данные.
Простите, Я не понял, как сделать: Вы имеете ввиду вообще отказаться от использования библиотеки DallasTemperature ? Я поковырялся в самой библиотеке DallasTemperature.cpp. Попытался заменить delay на millis. Заменить, то заменил, но ничего не изменилось. PHP: /// #define CASE_9_UPDATE_TIME 94 unsigned long CASE_9LastUpdateTime = 0; #define CASE_10_UPDATE_TIME 188 unsigned long CASE_10LastUpdateTime = 0; #define CASE_11_UPDATE_TIME 375 unsigned long CASE_11LastUpdateTime = 0; #define CASE_12_UPDATE_TIME 750 unsigned long CASE_12LastUpdateTime = 0; // Wait a fix number of cycles till conversion is complete (based on IC datasheet) switch (*bitResolution) { case 9: if (millis() - CASE_9LastUpdateTime > CASE_9_UPDATE_TIME) { CASE_9LastUpdateTime = millis(); break; } case 10: if (millis() - CASE_10LastUpdateTime > CASE_10_UPDATE_TIME) { CASE_10LastUpdateTime = millis(); break; } case 11: if (millis() - CASE_11LastUpdateTime > CASE_11_UPDATE_TIME) { CASE_11LastUpdateTime = millis(); break; } case 12: if (millis() - CASE_12LastUpdateTime > CASE_12_UPDATE_TIME) { CASE_12LastUpdateTime = millis(); break; } } Подскажите, пожалуйста, поподробнее, как избавится от задержек. Спасибо.
Выбросьте библиотеку DallasTemperature, используйте библиотеку OneWire, операции раскидайте по циклу как хотите, задав свои задержки. Никогда не смешивайте операции ввода и вывода внутри библиотек.
Спасибо за совет. Тоже склонялся уже выбросить эту библиотеку Но разве с помощью OneWire можно подключить два датчика ?
Скетч с одной библиотекой OneWire получился такой. Да работает без задержек. Но как сюда добавить второй датчик ? PHP: #include <IRremote.h> // IR #include <Wire.h> // I2C #include <LiquidCrystal_I2C.h> // LCD #include <OneWire.h> #define IR_PIN 5 //DS18b20 OneWire ds(4); bool LampState4 = false; int Temp; LiquidCrystal_I2C lcd(0x27, 20, 4); #define LCD_UPDATE_TIME 1000 unsigned long lcdLastUpdateTime = 0; IRrecv irrecv(IR_PIN); decode_results results; void setup() { Wire.begin(); lcd.init(); lcd.backlight(); // вкл. подсветку LCD (noBack-выкл) lcd.clear(); pinMode(IR_PIN, INPUT); irrecv.enableIRIn(); // Включаем ресивер } void loop() { if (irrecv.decode(&results)) { if (results.value == 565343) LampState4 = !LampState4; if (LampState4) { lcd.noBacklight(); // выкл. подсветку } else { lcd.backlight(); // вкл. подсветку } irrecv.resume(); // Получаем следующее значение } setTemperature(); // вызываем функцию работы с DS18b20 } void setTemperature() // DS18B20 { byte data[2]; ds.reset(); ds.write(0xCC); ds.write(0x44); // обращаемся к датчикам раз в 1000 мс, т.к. 750 может быть недостаточно if (millis() - lcdLastUpdateTime > LCD_UPDATE_TIME) { lcdLastUpdateTime = millis(); ds.reset(); ds.write(0xCC); ds.write(0xBE); data[0] = ds.read(); data[1] = ds.read(); Temp = (data[1] << 8) + data[0]; Temp = Temp >> 4; } // Температура lcd.setCursor(11, 0); lcd.print("T1: "); lcd.print(Temp); // отображение температуры lcd.print("C "); }
Аллилуйя. Добился чего хотел. Выкладываю скетч, может кому-то пригодится, кто захочет интегрировать в свой проект датчики температуры DS18B20 более 2 шт, не опасаясь задержек в работе других компонентов проекта (хотя может тема дубль, тогда извините). В данном варианте не требуется подключение "тормознутой" библиотеки DallasTemperature, только OneWire. PHP: #include <OneWire.h> #include <IRremote.h> // IR #include <Wire.h> // I2C #include <LiquidCrystal_I2C.h> // LCD #define IR_PIN 5 OneWire ds (4); byte data[12]; byte addr1[8] = {0x28, 0xFF, 0xF2, 0x9C, 0x67, 0x14, 0x04, 0xF7}; byte addr2[8] = {0x28, 0xFF, 0xA1, 0x9B, 0x67, 0x14, 0x04, 0xAA}; unsigned int raw; float temp1, temp2; bool LampState4 = false; LiquidCrystal_I2C lcd(0x27, 20, 4); #define LCD_UPDATE_TIME 1000 unsigned long lcdLastUpdateTime = 0; IRrecv irrecv(IR_PIN); decode_results results; void setup() { Wire.begin(); lcd.init(); lcd.backlight(); // вкл. подсветку LCD (noBack-выкл) lcd.clear(); irrecv.enableIRIn(); // Включаем ресивер } void loop() { temp1 = DS18B20(addr1); temp2 = DS18B20(addr2); if (irrecv.decode(&results)) { if (results.value == 565343) LampState4 = !LampState4; if (LampState4) { lcd.noBacklight(); // выкл. подсветку } else { lcd.backlight(); // вкл. подсветку } irrecv.resume(); // Получаем следующее значение } lcd.setCursor(9, 0); lcd.print("T1: "); lcd.print(temp1); // отображение температуры lcd.print("C "); lcd.setCursor(9, 1); lcd.print("T1: "); lcd.print(temp2); // отображение температуры lcd.print("C "); } //================================================================================== // Считывание температуры //================================================================================== float DS18B20(byte *adres) { if (millis() - lcdLastUpdateTime > LCD_UPDATE_TIME) // обращаемся к датчикам раз в 1000 мс { lcdLastUpdateTime = millis(); ds.reset(); ds.select(adres); ds.write(0x44, 1); // start conversion, with parasite power on at the end } ds.reset(); ds.select(adres); ds.write(0xBE); // Read Scratchpad for (byte i = 0; i < 9; i++) // можно увеличить точность измерения до 0.0625 *С (от 9 до 12 бит) { // we need 9 bytes data[i] = ds.read (); } raw = (data[1] << 8) | data[0];//=======Пересчитываем в температуру float celsius = (float)raw / 16.0; return celsius; } В качестве проверки работоспособности скетча, в данном случае, моргаем подсветкой LCD экрана посредствам нажатия кнопки ИК-пульта (все быстро, как и без датчиков ) P.S. источник
Да есть такое. Нужно играться с задержкой: PHP: #define LCD_UPDATE_TIME 1000 Я уменьшил до 750 мс, так у меня работают два датчика. Бывает при включении Arduino, второй датчик "запустится" только через секунду, две. Пока не знаю, как доработать код.
При изменении (#define LCD_UPDATE_TIME 1000) ничего не изменилось, как показывал 85.00 градусов так и показывает. Первый датчик исправно отображает температуру. При запуске другой программы с мониторингом через COM порт отображает оба датчика исправно.
Полностью удалить задержку и все будет работать как часы PHP: #include <OneWire.h> #include <IRremote.h> // IR #include <Wire.h> // I2C #include <LiquidCrystal_I2C.h> // LCD #define IR_PIN 5 OneWire ds (4); byte data[12]; byte addr1[8] = {0x28, 0xFF, 0xF2, 0x9C, 0x67, 0x14, 0x04, 0xF7}; // ID индивидуально для каждого датчика byte addr2[8] = {0x28, 0xFF, 0xA1, 0x9B, 0x67, 0x14, 0x04, 0xAA}; unsigned int raw; float temp1, temp2; bool LampState4 = false; LiquidCrystal_I2C lcd(0x27, 20, 4); IRrecv irrecv(IR_PIN); decode_results results; void setup() { Wire.begin(); lcd.init(); lcd.backlight(); // вкл. подсветку LCD (noBack-выкл) lcd.clear(); irrecv.enableIRIn(); // Включаем ресивер } void loop() { temp1 = DS18B20(addr1); temp2 = DS18B20(addr2); if (irrecv.decode(&results)) { if (results.value == 565343) LampState4 = !LampState4; if (LampState4) { lcd.noBacklight(); // выкл. подсветку } else { lcd.backlight(); // вкл. подсветку } irrecv.resume(); // Получаем следующее значение } lcd.setCursor(9, 0); lcd.print("T1: "); lcd.print(temp1); // отображение температуры lcd.print("C "); lcd.setCursor(9, 1); lcd.print("T1: "); lcd.print(temp2); // отображение температуры lcd.print("C "); } //================================================================================== // Считывание температуры //================================================================================== float DS18B20(byte *adres) { ds.reset(); ds.select(adres); ds.write(0x44, 1); // start conversion, with parasite power on at the end ds.reset(); ds.select(adres); ds.write(0xBE); // Read Scratchpad for (byte i = 0; i < 9; i++) // можно увеличить точность измерения до 0.0625 *С (от 9 до 12 бит) { // we need 9 bytes data[i] = ds.read (); } raw = (data[1] << 8) | data[0];//=======Пересчитываем в температуру float celsius = (float)raw / 16.0; return celsius; } Автор скетча, видимо, преднамеренно ввел задержку в 1 секунду, что сбило меня с толку. Я думал, что она нужна для подготовки данных с термодатчиков; никакой задержки здесь не нужно.
float DS18B20(byte *adres) - не могу понять, что это значит? ранее adres в переменных не фигурировал ds.select(adres) - и как это работает? Ведь до этого вы прописывали адрес датчика в массив addr1? Где связь между addr1 и adres? Объясните пожалуйста новичку)
каждый датчик имеет свой уникальный адрес. вот его и определяют и по нему работают с датчиком. поэтому на один пин можно повесить гроздь этих датчиков
Это мне понятно Код (PHP): #include <OneWire.h> OneWire ds (10); byte data[12]; byte addr1[8] = {0x28, 0xC6, 0xAE, 0x0A, 0x05, 0x00, 0x00, 0x8C}; byte addr2[8] = {0x28, 0x7D, 0xA6, 0x0A, 0x05, 0x00, 0x00, 0x4D}; unsigned int raw; float temp1, temp2; void setup() { Serial.begin (9600); } void loop(){ temp1 = DS18B20(addr1); temp2 = DS18B20(addr2); Serial.print("Temp1="); Serial.print(temp1); Serial.print("Temp2="); Serial.println(temp2); } //================================================================================== // Считывание температуры //================================================================================== float DS18B20(byte *adres){ ds.reset(); ds.select(adres); ds.write(0x44,1); // start conversion, with parasite power on at the end delay(1000); ds.reset(); ds.select(adres); ds.write(0xBE); // Read Scratchpad for (byte i = 0; i < 9; i++) { // we need 9 bytes data[I] = ds.read (); } raw = (data[1] << 8) | data[0];//=======Пересчитываем в температуру float celsius = (float)raw / 16.0; return celsius; } В переменных указаны массивы addr1 и addr2 - в этих массивах "жестко" прописаны адреса датчиков. А вот дальше - когда идет участок считывания температуры: строка Код (Text): float DS18B20(byte *adres) - что такое adres (да и вообще что значит это выражение)? Точнее я понимаю что это похоже адрес датчика, но откуда откуда взялась эта переменаня adres? Ранее в коде она НИГДЕ (в том числе в описании переменных) не фигурировала. Как же это работает?
Почитал (саму библиотеку)... ничего не понял. В описании на сайте автора вообще ни слова про это. float DS18B20(byte *adres) - Товарищи, объясните что значит это выражение? Желательно на пальцах, float потому что имеем дело с дробным числом (температурой)? DS18B20 - название массива?
Это функция, которая принимает один параметр (указатель на byte) и возвращает вещественное число. Читайте про функции в С/С++ и все поймете.