Когда эффективнее подавать запрос на датчик ds18b20?
- Войдите на сайт для отправки комментариев
Друзья, подскажите чисто теоретически, когда это лучше сделать? В примерах библиотеки oneware.h запрос на измерение температуры производится в самом начале loop(). А потом по прошествии некоторого времени (750-1000 мсек), нужного датчику, чтобы измерить температуру, пересчитать и выдать результат, считываем показания. Вариантов отсчета времени много (прерывание по таймеру, delay, по millis() и т.д.). Получается, что если код в цикле loop () короткий, то запрос на измерение температуры посылается много кратно, а считывание результата на порядки реже. Можно ли посылать запрос после считывания результата, в цикле, например, "if", в котором отсчитываем эти 750-1000 мсек? Представляется, что такой запрос будет единственным, а не многократным. Что немного, но сэкономит время. Или я что-то упустил?
В качестве примера (взято из Интернета):
#include <OneWire.h>
// Чтение данных с температурных датчиков типа 1-Wire: DS18S20, DS18B20, DS1822
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// Библиотека DallasTemperature может сделать это все за вас!
// http://milesburton.com/Dallas_Temperature_Control_Library
OneWire ds(10); // на 10-ом контакте (если необходимо, подключите резистор на 4,7 кОм)
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
if ( !ds.search(addr)) {
Serial.println("No more addresses."); // "Адресов больше нет."
Serial.println();
ds.reset_search();
delay(250);
return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!"); // "CRC не корректен!"
return;
}
Serial.println();
// первый ROM-байт, определяет, с каким чипом мы имеем дело:
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // " Чип – DS18S20" или старый DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20"); // " Чип – DS18B20"
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822"); // " Чип – DS1822"
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device."); // "Устройство не принадлежит семейству DS18x20."
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // запускаем конверсию и включаем паразитное питание
delay(1000); // 750 миллисекунд может хватить, а может и нет;
// здесь можно использовать ds.depower(),
// но об этом позаботится сброс
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // считываем scratchpad-память
Serial.print(" Data = "); // " Данные = "
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // нам нужно 9 байтов
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// конвертируем данные в температуру; поскольку результат - это
// 16-битное целое знаковое число, оно должно быть записано в типе
// данных "int16_t", который всегда будет 16-битным – даже если
// данные скомпилированы на 32-битном процессоре.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // разрешение по умолчанию – 9 бит
if (data[7] == 0x10) {
// регистр "count remain" дает полное 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;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = "); // "Температура = "
Serial.print(celsius);
Serial.print(" Celsius, "); // " по Цельсию, "
Serial.print(fahrenheit);
Serial.println(" Fahrenheit"); // " по Фаренгейту"
}
То есть, строчки № 63-65 перенестри в позицию № 114?
Заранее спасибо!
То есть, строчки № 63-65 перенести в позицию № 114? Понятно, что при первом чтении результата мы получим ноль, но потом, вроде, все должно работать штатно.
Заранее спасибо!
Если не выставлен флаг busy, послал запрос, запомнил время, выставил флаг busy. Через N ms, если флаг busy выставлен, считал результат, сбросил флаг.
Если не выставлен флаг busy, послал запрос, запомнил время, выставил флаг busy. Через N ms, если флаг busy выставлен, считал результат, сбросил флаг.
Ага, это я тоже рассматривал. Но тут появляется новая переменная (флаг). В моем предложении - лишняя. Или я что-то по неразумности и неквалифицированности сказанул в топике не то?
Я тему вообще не понял. "Когда лучше пить чай?" - вот примерно так она для меня выглядит. А с "лишней переменной" вообще добили - у Вас норматив? Во сколько переменых нужно уложиться? В курсе ли Вы, что МК эти переменные не только не считает, но и не видит, в принципе?
посмотрите пример блинк без делея и сделайте аналогично чтение показаний датчика.
Ссылку на тему Dimax походу не читали.((((
посмотрите пример блинк без делея и сделайте аналогично чтение показаний датчика.
Насколько я вас понимаю, предлагается или такая конструкция:
long interval; void setup() { } void loop() { // запрос на чтение температуры датчиком unsigned long currentMillis = millis(); if(millis() - interval > 1000) { // считываем показания датчика и показываем их так или иначе interval=millis(); } }или такая:
long interval; void setup() { } void loop() { unsigned long currentMillis = millis(); if(millis() - interval > 1000) { // считываем показания датчика и показываем их так или иначе interval=millis(); // запрос на чтение температуры датчиком } }Но в данном случае сам способ отсчета времени я не имел ввиду (их может быть несколько). Речь идет о запросе на измерение температуры в начале лупа (как в примерах бибилиотек) или сразу после считывания результата.
Ссылку на тему Dimax походу не читали.((((
Буду признателен, если ткнете меня в нее носом :)
Ссылку на тему Dimax походу не читали.((((
Буду признателен, если ткнете меня в нее носом :)
Тыц, а еще #10 и #11, в Вашей же теме.(((
Тыц, а еще #10 и #11, в Вашей же теме.(((
Спасибо, там-то я побывал (думал, Димакс еще где-то полезное про это написал). Но беда в том, что пока с портами и адресами у меня не сильно здорово :( То есть. основная мысль оттуда понятна, но как ее самому себе разжевать - еще не знаю. Конечно, буду образовавываться, но пока задал более приземленный (для меня) вопрос.
Там ниже, еще на первой странице, есть подпрограмма на миллисе, по образу и подобию, кому таймер собаки занимать не хотца.
Но в данном случае сам способ отсчета времени я не имел ввиду (их может быть несколько). Речь идет о запросе на измерение температуры в начале лупа (как в примерах бибилиотек) или сразу после считывания результата.
В упрощённых блокирующих примерах библиотек, как правило, стоит delay(), который придерживает следующий запрос к датчику на N ms.
Фактически всегда получается такая конструкция:
while (true) { // запрос delay(1000); // время на конверсию // получение результата }Это практически то же самое, что и неблокирующая реализация:
while (true) { unsigned long currentMillis = millis(); if(millis() - startWaitTime > 1000UL) { startWaitTime = millis(); // чтение датчика // запрос на чтение температуры датчиком } }Но, обратите внимание на то, что в ней чтение датчика приходится ставить впереди запроса. Корректно ли это?
А если перепишем вот так?
readingDone = true; while (true) { unsigned long currentMillis = millis(); if (readingDone) { startWaitTime = millis(); // запрос на чтение температуры датчиком readingDone = false; } else { if (millis() - startWaitTime > 1000UL) { // чтение датчика readingDone = true; } } }Там ниже, еще на первой странице, есть подпрограмма на миллисе, по образу и подобию, кому таймер собаки занимать не хотца.
Спасибо, прочел уже.
Спасибо, прочел уже.
Помогло, али опять мимо?
Помогло. Во всяком случае, в смысле воспитания. Но, тем не менее, там упорно используется флаг. Мне он по-прежнему кажется лишним, если запрашивать сенсор сразу после его прочтения посредством "старушки"- миллис :).
#include <OneWire.h> OneWire ds(2); // выбор пина ардуино, на котором висит шина 1-wire // ниже перечисление температур 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 }; // например, чтобы использовать переменную температуры на улице, пишем так: Serial.print (Temper[UlicaC]); uint32_t prev1Wire_polling = 0; byte interval_1wire = 4; // интервал опроса шины 1-wire, *2 (сек.) в данном случае 8 сек boolean n=0; void setup() { Serial.begin(9600); } void loop() { dallas(); } void dallas() { 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_; // всё, тут уже пишем температуру в переменную } } } } Serial.print ("Temper AntiFreeze = "); Serial.println (Temper[FreezeC]); // так для примера prev1Wire_polling = millis(); } }П Но, тем не менее, там упорно используется флаг. Мне он по-прежнему кажется лишним, если запрашивать сенсор сразу после его прочтения посредством "старушки"- миллис :).
вам что так часто температуру надо читать? есть флаг и ладно. Работает хорошо, зачем воду мутить?
Помогло. Во всяком случае, в смысле воспитания. Но, тем не менее, там упорно используется флаг. Мне он по-прежнему кажется лишним, если запрашивать сенсор сразу после его прочтения посредством "старушки"- миллис :).
Вы про какой флаг, их там два, один в теле и определяет выбор исполняемой ветки, второй передает интервал возврата, его можно убрать.
Друзья, спасибо. Тайм-аут: бегу в операционную. Вечером все проштудирую.!
Вот такой пример чтения далласа через определенное количество сек. Температура в сотых градуса int.
#include <OneWire.h> #define DS_PIN 4 OneWire ds(DS_PIN); int temp; word currMillis, prevMillis, intervalMs = 10; byte second, countCycle; void setup() { Serial.begin(9600); startDS(); } void loop() { currMillis = millis(); if(currMillis - prevMillis >= intervalMs){//10ms prevMillis += intervalMs; switch (countCycle){ // case 0 ... (TOT_STR_OLED-1): // printLCD(countCycle); // break; case 5: if((second % 3) == 0)//закомент.если нужно каждую сек temp = getDS();//кажд.3 сек. В сот *С Serial.println(temp); break; case 6: if((second % 3) == 2)//закомент.если нужно каждую сек startDS(); break;//за 1 сек до чтения // case 10: // if((second % 3) == 0) read_Si7021();//20 раз в мин // break; } if(++countCycle >= 100){//прошла 1 сек countCycle = 0; if(++second >= 60) second = 0;; //или с RTC } } } //============================= void startDS(){//Т котла ds.reset(); //команда на преобразов. = 2200 mksec ds.write(0xCC);// пофиг на адреса (SKIP ROM) ds.write(0x44);// начать преобразование } //======================= int getDS(){//возвр. полож. и отрицательную Т в сотых *С int t = 0;//При опросе раз в 2 сек Т датчика поднимается на 0.4С ds.reset(); // чтение3250 mks ds.write(0xCC); ds.write(0xBE); t = ds.read() | (ds.read()<<8); //if(t == 0x550) error;//+85C = B10101010000 (первое измерение после подачи питан) //if(t == 0xFFFF) //(-1 == 0xFFFF) нет датчика при вкл. подтяжке if(t == 0xFFFF){// -1 если есть подтяжка t = -10000;//ошибка -100*C }else /*if(t < 0x550)*/{ //для Т воздуха int tFract = ((t & 0x0F) *100 +8) / 16;// fractional - дробная t = t / 16 *100 + tFract; } return t;//Т в сотых *С }А если перепишем вот так?
readingDone = true; while (true) { unsigned long currentMillis = millis(); if (readingDone) { startWaitTime = millis(); // запрос на чтение температуры датчиком readingDone = false; } else { if (millis() - startWaitTime > 1000UL) { // чтение датчика readingDone = true; } } }Тогда при опросе по таймеру раз в пять минут получаем данные пятиминутной свежести.
...и? Перепишите так, как полагается в продакшне, если считаете, что объясняющий принцип работы флага пост должен содержать трёхстраничный код, который делает вообще всё правильно.
Я делаю всегда так используя или TimerOne, или миллис:
перввый запуск счета в сетупе и там же запуск задержки на требуемое время обновления температуры, например «раз в минуту».
когда время наступило считываю готовую температуру , запускаю измерение и новую задержку.
процессы достаточно медленно-меняющиеся и развминуту видеть , что было 59.250 сек назад мне вполне достаточно.
Тогда при опросе по таймеру раз в пять минут получаем данные пятиминутной свежести.
...и? Перепишите так, как полагается в продакшне, если считаете, что объясняющий принцип работы флага пост должен содержать трёхстраничный код, который делает вообще всё правильно.
не должен!
Но ТС человек настойчивый упорно не желает делать по простому, с флагом
Часто делаю в лупе функцией из 8! шагов, что бы не тормозить сам луп.