DS18B20 Датчик температури повертається як функція float, повертаючи null 50% часу

Я тільки що отримав DS18B20 датчик температури і намагаюся змінити приклад коду, щоб використовувати функцію замість цього. Нижче наведено мою функцію getTemp . Це працює, але повертає результати з значенням "0", наприклад:

Температура = 72,39
  Температура = 0.00

Якщо я додаю Serial.print (фаренгейт); у функції, я завжди забезпечую правильну температуру. Я хотів, що це може бути пов'язано з необхідністю затримки, але додавання затримки (5000); в моєму циклі не допомогло.

Я припускаю, що це щось просто, я не розумію, як повертається floats .

#include 

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire  ds(2); //on pin 10 (a 4.7K resistor is necessary)

void setup(void) {
  Serial.begin(9600);
}

float getTemp(char tScale) {
  byte i;
  byte present = 0;
  byte type_s = 0;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  if ( !ds.search(addr)) {
    ds.reset_search();
    delay(250);
    return false;
  }

  ds.reset();
  ds.select(addr);
  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
 //because the result is a 16 bit signed integer, it should
 //be stored to an "int16_t" type, which is always 16 bits
 //even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3;//9 bit resolution default
    if (data[7] == 0x10) {
     //"count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
   //at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7; //9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3;//10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1;//11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw/16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  if (tScale == 'C') {
    return celsius;
  }
  else if (tScale == 'F') {
    return fahrenheit;
  }

}
void loop(void) {
    Serial.print("Temperature = ");
    Serial.println( getTemp( 'F' ) );


}

Редагувати: Цікаво, що додавання у цикл оператора if виправляє це. Я б хотів ще зрозуміти, що відбувається:

void loop(void) {
  if ( getTemp( 'F' ) == 0 ){
    Serial.print( "Temperature = " );
    Serial.println( getTemp( 'F' ) );
  }
}
0
Є очевидно багато передбачуваних пристроїв "DS18B20" на ринку, які не відповідають строкам опублікованої специфікації. Щоб спробувати скористатися ними, потрібно сповільнити речі. Можна дещо компенсувати витрати часу на це, запустивши в нижньому бітному режимі, але деякі з опублікованого прикладу, який з'являється для обробки різної ширини бітів, насправді жахливо неправильно тлумачить що-небудь, окрім найширшого, і має бути виправленим. Ні, у мене немає відремонтованої копії під рукою, щоб цитувати.
додано Автор rossp, джерело
Я думаю, що я маю на увазі те, що якщо getTemp встановлено на 0, то правильна температура відображається в послідовному режимі (ніколи не показуючи Temperature = 0.00 ).
додано Автор Towell, джерело
Не могли б Ви пояснити, що Ви розумієте під "редагуванням" у Вашій редакції? Оскільки ваш getTemp() іноді повертає 0 , очевидно, що ви фільтруєте нуль, перевіряючи getTemp ('F') == 0 .
додано Автор passing through, джерело
Таким чином, ви пропускаєте проблематичні екземпляри ! Ds.search (addr) (двічі безпосередньо вибираючи сенсор), ігноруючи основну проблему. :)
додано Автор passing through, джерело
@Chris Stratton: Я думаю, що це гарна ідея розглянути фактичну проблему комунікації DS18B20. BandonRandon: Чому б вам не спробувати бібліотеку DallasTemperature? Він навіть поставляється з тестером ескіз та інші корисні речі.
додано Автор passing through, джерело

1 Відповіді

У вас є переривчасті проблеми з комунікацією.

Пошук по адресі іноді виходить з ладу і getTemp() повертає помилку. У C ++ (і на багатьох інших мовах) false буде неявно передано до (int) 0 , (float) 0.0f і так далі.

Вашу функцію getTemp() також важко налагоджувати, оскільки кілька операторів повернення мають різне значення.

Після затримки (250); ви зробите return false; , щоб пропустити решту.

У прикладі на сторінці https://www.pjrc.com/teensy/td_libs_OneWire.html значення оператора return відрізняється. Там повернення відбувається в межах функції void loop() , де це просто означає переривання поточного виконання (без повернення значення) і продовження наступного циклу.

Хоча, як правило, потрібно мати кілька кодів return , іноді це може бути проблематично, і я рекомендую уникати цього.

Якщо ви хочете очистити цю функцію, зберігаючи при цьому можливість виявлення помилки, у вас є кілька варіантів (замовлення від більшості до найменш рекомендованих):

  • do the setup/checking in a different function (and only call the second one if the first one succeeded), i.e. if (isReady()) { Serial.println(getTemp()); }
  • set a separate error variable, i.e. error = true; return 0; (and then check error later)
  • define a 'default' value that you interpret as an error (and never expect to be a temperature), i.e. return NAN;//not a number
1
додано
Замість того, щоб -460.0f , що виглядає як нерозумне значення, я повертаю NAN (тобто не число ). Він більш чітко передає значення "недійсне значення". Serial.print() відображає його як “nan”.
додано Автор Sprogz, джерело
Спасибі перейшли на бібліотеку Майлза Бертона, і все працює, як очікувалося, і мій код виглядає набагато чистіше.
додано Автор Towell, джерело
Насправді існує причина, чому ви використовуєте датчик на важкому шляху і не використовуєте для нього бібліотеку (як у OneWire)? Є бібліотеки температури Далласа, які використовують OneWire, напр. github.com/milesburton/Arduino-Temperature-Control-Library .
додано Автор passing through, джерело
Так, поза діапазоном було тільки перше, що я придумав. А оскільки це моє найменш рекомендоване рішення, я все ще вважаю його нижчим навіть при використанні NAN. Я відповідно відредагую відповідь.
додано Автор passing through, джерело