Сокращение времени считывания показаний датчиков температуры 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 и т. д., и все мои первоначальные попытки сделать это потерпели неудачу.
Можно ли убрать эту задержку после считывания каждого датчика?
@davidgo, 👍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, но она удовлетворяет моим требованиям к измерению температуры (пока что) и упрощает код моего приложения, заключая в черный ящик описанные выше методы.
Выполнять поиск каждый раз довольно неэффективно. Функция поиска нужна, если вы не знаете адрес устройства, и это занимает некоторое время. В вашем случае, по-видимому, адреса никогда не изменятся. Найдите адреса и жестко закодируйте их в свой код. Или, если это нецелесообразно, сохраните их в 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
В случае, если "Время преобразования температуры (tCONV)" каждого разрешения недостаточно быстро ([MAX] 9-бит: 93,75 мс; 10-бит: 187,5 мс; 11-бит: 375 мс; 12-бит: 750 мс), вы можете использовать больше датчиков.
Например, чтобы получить время полураспада (для 9-битного): 47 мс:
- Вы можете использовать два датчика в одной и той же точке измерения (они могут работать параллельно, если программное обеспечение может работать с каждым из них). При считывании данных с одного программа начинает преобразовывать другой.
Каждый из них имеет свое нормальное время преобразования, но при выполнении показаний с чередованием можно получить более короткое время чтения.
Для 8 датчиков можно достичь времени менее 11,75 мс (для 9 бит).
- Объединение кода для нескольких датчиков в одной программе
- Код считывания датчика DHT22 странно интерпретирует отрицательные значения (распространенная проблема)
- Запуск прерываний с помощью DHT-11
- Проблема с условием if
- Возможно ли, чтобы температура тела, кровяное давление, оксиметр и датчик частоты пульса находились только в одном Arduino UNO?
- Как объявить массив переменного размера (глобально)
- Программирование Arduino с использованием Python, а не C/C ++
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
Какую библиотеку вы используете? [Этот](http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library), похоже, по умолчанию выполняет «массовое» чтение., @Gerben
Уменьшение битового разрешения сократит требуемое время, однако некоторые библиотеки получают совершенно неправильное преобразование, и в этом случае их необходимо исправить., @Chris Stratton