Сокращение времени считывания показаний датчиков температуры DS18B20.

У меня есть несколько датчиков температуры, подключенных к Arduino. Я разделил их на 3 секции, в каждой из которых есть 2-4 датчика (из-за расстояния). Это работает, но код, который я использую, кажется мне очень неэффективным, особенно в отношении того, сколько времени требуется для считывания всех датчиков.

У меня есть 3 блока кода один за другим (которые модифицированы из какого-то кода онлайн), которые выглядят так, как показано ниже - конечно, за исключением имени класса 1wire.

// Dallas 1 Wire (основная область):

 // ds.reset_search();
 // задержка(250);
  while (ds.search(addr))
  {
    for( i = 0; i < 8; i++) {
      Serial.print(addr[i], HEX);
    }

    if (OneWire::crc8(addr, 7) != addr[7]) {
        Serial.println("CRC is not valid!");
        return;
    }

    ds.reset();
    ds.select(addr);
    ds.write(0x44, 0);        // начинаем преобразование, в конце с включенным питанием паразита

    delay(1000);     // может 750 мс хватит, может нет
    // здесь мы могли бы выполнить ds.depower(), но об этом позаботится сброс.

    present = ds.reset();
    ds.select(addr);    
    ds.write(0xBE);         // Чтение блокнота

    for ( i = 0; i < 9; i++) {           // нам нужно 9 байт
      data[i] = ds.read();
    }
    raw = (data[1] << 8) | data[0];
    if (type_s) {
      raw = raw << 3; // 9-битное разрешение по умолчанию
      if (data[7] == 0x10) {
        // "количество оставшихся" дает полное 12-битное разрешение
        raw = (raw & 0xFFF0) + 12 - data[6];
      }
    } else {
      byte cfg = (data[4] & 0x60);
      // при более низком разрешении младшие биты не определены, поэтому обнулим их
      if (cfg == 0x00) raw = raw & ~7;  // 9-битное разрешение, 93,75 мс
      else if (cfg == 0x20) raw = raw & ~3; // 10-битное разрешение, 187,5 мс
      else if (cfg == 0x40) raw = raw & ~1; // 11-битное разрешение, 375 мс
      //// по умолчанию разрешение 12 бит, время преобразования 750 мс
    }
    celsius = (float)raw / 16.0;
    Serial.print(":");
    Serial.print(celsius);
    Serial.print(",");
  }

Я заметил, что после считывания данных с каждого датчика возникает задержка в 1000 мс, и мне интересно, можно ли уменьшить ее до одной задержки в 750 мс для всех датчиков. Мои первоначальные попытки сделать это не увенчались успехом, но я признаюсь, что не совсем понимаю ds.reset, ds.select и т. д., и все мои первоначальные попытки сделать это потерпели неудачу.

Можно ли убрать эту задержку после считывания каждого датчика?

, 👍3

Обсуждение

Какую библиотеку вы используете? [Этот](http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library), похоже, по умолчанию выполняет «массовое» чтение., @Gerben

Уменьшение битового разрешения сократит требуемое время, однако некоторые библиотеки получают совершенно неправильное преобразование, и в этом случае их необходимо исправить., @Chris Stratton


3 ответа


Лучший ответ:

3

После почти года и ряда экспериментов я узнал немного больше об использовании этих устройств:

Выдача датчикам команды Skip ROM, за которой следует команда Convert T, запускает одновременное преобразование температуры всеми устройствами (стр. 11 таблицы данных). Затем вам нужно всего лишь подождать один период задержки {750 375 188,94} мс для {12,11,10,9}-битного преобразования соответственно, прежде чем вы сможете начать считывание температур.

Если устройства получают паразитное питание, во время преобразования шине потребуется сильное подтягивание; подтягивания 4,7 кОм недостаточно (стр. 5 таблицы данных).

Вывод arduino может выдавать 40 мА, и я обнаружил, что второй вывод, напрямую обходя подтягивание 4,7 кОм без предложенного транзистора, будет подавать достаточный ток как минимум для 3 датчиков (столько, сколько я пробовал до сих пор) и Я предполагаю, что эту технику можно было бы распространить на большее количество булавок. Сильный подтягивающий сигнал должен быть включен в течение 10 мкс после команды Convert T и поддерживаться на протяжении всего преобразования. Спецификация 10uSec в значительной степени означает, что вы должны сделать это в библиотеке.

У меня есть сокращенная библиотека DS18B20, в которой я предполагаю, что датчики на шине связаны между собой, поэтому она устанавливает все их разрешения сразу и сразу начинает их преобразования, а также предполагает, что шина питается от паразитов. есть, поэтому он переключает указанный контакт как сильное подтягивание. Я отказываюсь от некоторой гибкости, которую могла бы обеспечить полная библиотека DSTemperature, но она удовлетворяет моим требованиям к измерению температуры (пока что) и упрощает код моего приложения, заключая в черный ящик описанные выше методы.

,

2

Выполнять поиск каждый раз довольно неэффективно. Функция поиска нужна, если вы не знаете адрес устройства, и это занимает некоторое время. В вашем случае, по-видимому, адреса никогда не изменятся. Найдите адреса и жестко закодируйте их в свой код. Или, если это нецелесообразно, сохраните их в EEPROM. А если даже это нецелесообразно, найдите адреса один раз в настройках.


Далее вам нужна задержка, пока вы снимаете показания температуры. Почему бы не сделать их параллельными? В цикле скажите всем устройствам снять показания. Затем подождите одну секунду. Затем прочитайте их все (в другом цикле). Таким образом, задержка в одну секунду распределяется между всеми вашими датчиками.

Однако на странице, на которую ссылается Гербен:

Нельзя использовать датчики DS1820 с простым подтягивающим резистором. Во время фазы «Конверсия» ему требуется больше энергии. И есть Application Note, в котором это подробно обсуждается.

Это говорит о том, что если вы используете паразитную мощность, мое предложение не будет работать слишком хорошо (если несколько устройств считывают показания, это ухудшит ситуацию).


Я нашел этот код на своем диске пару лет назад. Задержек между датчиками считывания вроде бы нет. В конце основного цикла есть задержка, в основном для того, чтобы остановить спам на последовательном мониторе.

Обратите внимание на комментарий:

Вызвать sensor.requestTemperatures(), чтобы отправить запрос глобальной температуры всем устройствам на шине

Посмотрите, подходит ли это вам.

#include <OneWire.h>
#include <DallasTemperature.h>
#include <Streaming.h>

// Провод данных подключен к порту 10 на Arduino
const byte ONE_WIRE_BUS = 10;
const byte TEMPERATURE_PRECISION = 10;
// Настройте экземпляр oneWire для связи с любыми устройствами OneWire (не только с микросхемами температуры Maxim/Dallas)
OneWire oneWire(ONE_WIRE_BUS);

// Передаем нашу ссылку oneWire в Dallas Temperature.
DallasTemperature sensors(&oneWire);

// массивы для хранения адресов устройств
DeviceAddress myThermometer [10];
int deviceCount;

void setup(void)
{

  // запускаем последовательный порт
  Serial.begin (115200);
  Serial << "Dallas Temperature IC Control Library Demo" << endl;

  // Запускаем библиотеку
  sensors.begin();

  // найти устройства на шине
  Serial << "Locating devices..." << endl;
  deviceCount = sensors.getDeviceCount();

  Serial << "Found " << deviceCount << " devices." << endl;

  // сообщаем о требованиях к питанию паразита
  Serial << "Parasite power is: " << (sensors.isParasitePowerMode() ? "ON" : "OFF") << endl; 

  // метод 1: по индексу

  for (int i = 0; i < deviceCount; i++)
  {
    if (sensors.getAddress(myThermometer [i], i))
    { 
      Serial << "Device " << i << " Address: ";
      printAddress(myThermometer [i]);
      Serial << endl;
      sensors.setResolution(myThermometer [i], TEMPERATURE_PRECISION);
    }
    else
      Serial << "Unable to find address for Device " << i << endl;
  }  // конец цикла

}

// функция для вывода адреса устройства
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    // дополнить адрес нулями, если необходимо
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}


void loop(void)
{ 

  // вызов Sensors.requestTemperatures() для выдачи глобальной температуры
  // запрос ко всем устройствам на шине
  sensors.requestTemperatures();

  // теперь получаем все температуры
  for (int i = 0; i < deviceCount; i++)
  {
    float tempC = sensors.getTempC(myThermometer [i]);
    if (tempC > -80)
    { 
      Serial << "Device " << i << " Temperature: " << tempC << endl;
    }
    else
      Serial << "Unable to find temperature for Device " << i << endl;
  }  // конец цикла

  delay (1000);
}
,

Спасибо за ваш ответ. Я не использую паразитную силу, но мои попытки параллельно читать показания не увенчались успехом — возможно, потому, что мои навыки C невелики и частично потому, что я с трудом понимаю, как работает код — или, может быть, это просто невозможно сделать. Сканирование датчиков при запуске может быть целесообразным на данном этапе, но я намеренно сканировал их в каждом цикле, чтобы иметь возможность «горячей замены» изменений., @davidgo

Посмотрите в техническом описании использование «сильного подтягивания» для подачи дополнительного тока на датчики с паразитным питанием. В своих устройствах я использую дополнительный выходной порт, подключенный так, чтобы обойти подтягивающий резистор (слабый подтягивающий), как сильный подтягивающий. В техническом описании показан выходной порт, переключающий транзистор, действующий как сильное подтягивание. На практике я обнаружил, что сам по себе порт обеспечивает достаточно тока для 3 (максимум, который я тестировал) устройств DS18b20., @JRobert

См. измененный пост с другим примером., @Nick Gammon


0

В случае, если "Время преобразования температуры (tCONV)" каждого разрешения недостаточно быстро ([MAX] 9-бит: 93,75 мс; 10-бит: 187,5 мс; 11-бит: 375 мс; 12-бит: 750 мс), вы можете использовать больше датчиков.

Например, чтобы получить время полураспада (для 9-битного): 47 мс:

  • Вы можете использовать два датчика в одной и той же точке измерения (они могут работать параллельно, если программное обеспечение может работать с каждым из них). При считывании данных с одного программа начинает преобразовывать другой.

Каждый из них имеет свое нормальное время преобразования, но при выполнении показаний с чередованием можно получить более короткое время чтения.

Для 8 датчиков можно достичь времени менее 11,75 мс (для 9 бит).

,