Помогите с if

vborn
Offline
Зарегистрирован: 11.08.2017

Здравствуйте! Задача скетча выдавать сообщение об открытии/закрытии двери (в последующем открывать/закрывать дверь) при достижении MIN/MAX температур.

  #include <OneWire.h>
  OneWire  ds(10);
  float temp [3];     // temperature from DS18B20 
  int m=0;            // Number of sensors
  float averageTemp;  //average temperature from sensors DS18B20
  int minTemp=24;        //MIN temperature in the room
  int maxTemp=28;        //MAX temperature in the room
  boolean doorPosition = false; // 0 - close; 1 - open

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

void loop() {
  int n=0;
  float sumTemp = 0;
  scanTemp ();
  
  for (n=0; n<m; n++) {
  sumTemp = sumTemp + temp[n];
  }
  
  averageTemp = sumTemp/m;

  for (n=0; n<m; n++) {
  Serial.print("Temperature from Sensor"); Serial.print(n+1);Serial.print("  ");
  Serial.println(temp[n]);
  }
  
  Serial.print("Average Temperature ");
  Serial.println(averageTemp);
  Serial.print("Number of sensors = ");
  Serial.println(m);
  Serial.print("doorPosition = ");
  Serial.println(doorPosition);
  Serial.println();
    
  if (averageTemp < minTemp) {
    if (doorPosition == true) {
  Serial.println("Door close!");
  Serial.println();
  doorPosition = false;
  }
    }

  else if (averageTemp > maxTemp){
    if (doorPosition == false) {
  Serial.println("Door open!");
  Serial.println();
  doorPosition=true;
  }
    }
    
  delay (5000);
}

По задумке сообщение "Door open!" должно выдаваться только один раз при достижении температуры maxTemp, для чего введена логическая переменная doorPosition. То есть проверяем больше ли температура чем maxTemp, потом проверяем закрыта ли дверь ( if (doorPosition == false)) и только потом "открываем" дверь.

Но сообщение "Door open!" выдается всегда когда температура больше maxTemp. Почему?

Где ошибка зарыта?

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

Что будет если поменять

else if (averageTemp > maxTemp){

на

if (averageTemp > maxTemp){

?

vborn
Offline
Зарегистрирован: 11.08.2017

Ничего. Изначально так и было.

Вообще изначально были функции

  if (averageTemp < minTemp) {
    closeDoor();
    }

  if (averageTemp > maxTemp){
    openDoor();
    }

И все работало так же, такое ощущение что при последющей итерации в loop doorPosition сбрасыватся на ноль.

Nosferatu
Offline
Зарегистрирован: 04.11.2012

vborn пишет:

... такое ощущение что при последющей итерации в loop doorPosition сбрасыватся на ноль.

Ну это легко проверить выводом в монитор, в какой строке true, а где false.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

vborn пишет:

такое ощущение что при последющей итерации в loop doorPosition сбрасыватся на ноль.

К чему ощущения, если ты выводишь doorPosition перед условиями? Так  покажи вывод. Все станет ясно.

...гы! опоздал. и даже цитата та же самая!

b707
Онлайн
Зарегистрирован: 26.05.2017

А число сенсоров m у вас специально установлено в ноль? не вижу. чтобы вы после где-то меняли на реальное значение

GarryC
Offline
Зарегистрирован: 08.08.2016

Для начала надо посмотреть код scanTemp() и лично меня смущает m=0.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

b707 пишет:

А число сенсоров m у вас специально установлено в ноль? не вижу. чтобы вы после где-то меняли на реальное значение

скетч не весь. Это в scanTemp() все зырыто (вероятно), и  там же утечка памяти, если она есть.

vborn
Offline
Зарегистрирован: 11.08.2017

wdrakula пишет:

vborn пишет:

такое ощущение что при последющей итерации в loop doorPosition сбрасыватся на ноль.

К чему ощущения, если ты выводишь doorPosition перед условиями? Так  покажи вывод. Все станет ясно.

...гы! опоздал. и даже цитата та же самая!

Temperature from Sensor1  25.94
Temperature from Sensor2  25.37
Temperature from Sensor3  25.50
Average Temperature 25.60
Number of sensors = 3
doorPosition = 0
 
Temperature from Sensor1  27.56
Temperature from Sensor2  26.69
Temperature from Sensor3  27.06
Average Temperature 27.10
Number of sensors = 3
doorPosition = 0
 
Temperature from Sensor1  28.75
Temperature from Sensor2  27.44
Temperature from Sensor3  27.81
Average Temperature 28.00
Number of sensors = 3
doorPosition = 0
 
Temperature from Sensor1  29.06
Temperature from Sensor2  27.75
Temperature from Sensor3  28.06
Average Temperature 28.29
Number of sensors = 3
doorPosition = 0
 
Door open!
 
Temperature from Sensor1  29.19
Temperature from Sensor2  27.94
Temperature from Sensor3  28.12
Average Temperature 28.42
Number of sensors = 3
doorPosition = 0
 
Door open!
 
Temperature from Sensor1  28.44
Temperature from Sensor2  27.37
Temperature from Sensor3  27.31
Average Temperature 27.71
Number of sensors = 3
doorPosition = 0
 
vborn
Offline
Зарегистрирован: 11.08.2017

GarryC пишет:

Для начала надо посмотреть код scanTemp() и лично меня смущает m=0.

Вот код функции сканирующей датчики.

void scanTemp (){
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;
    
  while (ds.search(addr)) {
    ds.reset();
    ds.select(addr);
    ds.write(0x44, 1);  
    delay(1000);
    present = ds.reset();
    ds.select(addr);    
    ds.write(0xBE);        
    for ( i = 0; i < 9; i++) {         
    data[i] = ds.read();
    }
    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);
    if (cfg == 0x00) raw = raw & ~7;
    else if (cfg == 0x20) raw = raw & ~3;
    else if (cfg == 0x40) raw = raw & ~1;
    
    }
    celsius = (float)raw / 16.0;
    temp [m] = celsius;
    m=m+1;
  }
  ds.reset_search();  
}

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Ну! Все верно. Значит сканТемп и портит где-то память! Давай погладим "какой ты Сухов" - то есть код сканТемп.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

никаких секретов!  м - никогда не возвращается к 0. переделывайте.

Я думаю, что ты хотел в 15 строке основного кода (первой строке loop() ) написать не

n=0;

, а

m=0;

 

vborn
Offline
Зарегистрирован: 11.08.2017

wdrakula пишет:

никаких секретов!  м - никогда не возвращается к 0. переделывайте.

Ура! Спасибо! В этом был косяк. 

В 15 строке все верно. Просто нужно было добавить в функцию scanTemp() строку

  m=0;  

перед while

void scanTemp (){
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;
  m=0;  
  while (ds.search(addr)) {....}

Но только я не понял при чем тут вообще моя булевая переменная doorPosition...

Но все работает!

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

vborn пишет:

Но только я не понял при чем тут вообще моя булевая переменная doorPosition...

Но все работает!

Компилятор С не проверяет правильность индекса массива. Ты писал в память, как температуру, а данные попадали неведомо куда. Например в место для doorPosition. ЕвгенийП, как-то раз приводил смешной код, где выводишь "i love you", а печатается "i hate you".

такие ошибки очень трудно искать.

Стало понятнее?

vborn
Offline
Зарегистрирован: 11.08.2017

wdrakula пишет:

Стало понятнее?

С этим да. Но тогда почему m всегда выдавала значение 3...

Number of sensors = 3

Если она не сбрасывалась в 0, то при каждом опросе датчиков m должна была увеличиваться на число их

3, 6, 9 и т.д.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

чорт его знает. Это меня тоже напрягло.

Но если код ошибочен, то предсказать все нюансы нельзя. Вот как-то так получалось. Важно, что теперь все должно быть нормально.

Да! И не забудь вставить в сканТемп органичение на три датчика!!!

Прямо в while(), в котором поиск проводишь.

vborn
Offline
Зарегистрирован: 11.08.2017

wdrakula пишет:

Да! И не забудь вставить в сканТемп органичение на три датчика!!!

Прямо в while(), в котором поиск проводишь.

А почему? Потому что temp [3]?

А если допустим будет 4 или 5 датчиков.

Вообще я все это затеял, если вдруг один из 3 датчиков отваливается, то автоматика будет работать дальше на 2 датчиках. И даже на одном)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

vborn пишет:

wdrakula пишет:

Да! И не забудь вставить в сканТемп органичение на три датчика!!!

Прямо в while(), в котором поиск проводишь.

А почему? Потому что temp [3]?

А если допустим будет 4 или 5 датчиков.

Вообще я все это затеял, если вдруг один из 3 датчиков отваливается, то автоматика будет работать дальше на 2 датчиках. И даже на одном)

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

Еще раз - С  не предусматривает контроль за индексом массива, полагая, что это сделает прогрмист. ОК?

... Да, и я не понял, как ограничение на максимальное количество датчиков, помешает тебе работать на 1 или 2?

vborn
Offline
Зарегистрирован: 11.08.2017

wdrakula пишет:

... Да, и я не понял, как ограничение на максимальное количество датчиков, помешает тебе работать на 1 или 2?

Никак. Понял, спасибо большое за ответ.

while (ds.search(addr) && m<3 )

так можно же?

GarryC
Offline
Зарегистрирован: 08.08.2016

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

И еще одно - Вы на редкость везучий человек, все таки перед использованием функции ds.search() в цикле следует до цикла вызывать ds.reset_search().

А собственно по теме - попробуйте отпечатать m перед вызовом scanTemp и сразу после него, я думаю, что будет 3 и 3.
Если так, то сделайте печать в функции сканирования перед
temp [m] = celsius;
после этого оператора и после инкремента - вангую 3 2 3 и это означает, что Вам дико не повезло (ошибку трудно обнаружить) или дико повезло (ошибка не приводит к падению программы) - кому что больше нравится .

vborn
Offline
Зарегистрирован: 11.08.2017

GarryC пишет:

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

Код конечно же страшноватый. Я в этой теме не больше месяца)

А в остальном вроде бы разобрались благодаря wdrakula :)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

так и нужно.

---------------

Ситуация с ошибкой была уникальна. Сохрани тот код, если не трудно, и опубликуй тут, вместе с версией ИДЕ.

Там такая комбинация случайностей, что ты вообще заметишь ошибку было маловероятно.... просто редкость в коллекцию.

 

 

vborn
Offline
Зарегистрирован: 11.08.2017

GarryC пишет:

перед использованием функции ds.search() в цикле следует до цикла вызывать ds.reset_search()

Для чего, простите? ) Ну чтобы знать. 

Код в scanTemp скопировал из готового шаблона библиотеки OneWare, удалив (на мой взгляд) ненужное. И добавив чуток своего. В целом для меня в этом коде еще много непонятного))

GarryC
Offline
Зарегистрирован: 08.08.2016

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

vborn пишет:

Для чего, простите? ) Ну чтобы знать. 

потому, что поиск - инкрементная функция, то есть такая, у которой следующий вызов зависит от результатов предыдущего.

То есть она хранит в невидимой зоне промежуточные данные.

Вот ресет и нужен, чтобы "обнулить" эти самые  - промежуточные данные.

У тебя первый вызов идет сразу после старта контроллера, поэтому  повезло. В этой истории у тебя вообще ведро везения. В казино ходить не пробовал?

GarryC
Offline
Зарегистрирован: 08.08.2016

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

Да, вы взяли пример из библиотеки, и это не говорит в ее пользу - крайне жаль, что авторы программы настолько не понимают ее работу.

GarryC
Offline
Зарегистрирован: 08.08.2016

Ну здесь, наверное, не сколько везение автора, а обнуление блока глобальных переменных при запуске программы, но полагаться на это я бы не стал.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

GarryC пишет:

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

Я разобрался, но для подтверждения нужен ассемблерный код. Идея такая, что 4 байта "в никуда" пишутся по-очереди. Сперва меняя м на 0, а потом остальные попадают куда нужно... иначе никак не объяснить. Ну это как ножик по пьяни кинуть в стенку и он воткнется.... ;)

vborn
Offline
Зарегистрирован: 11.08.2017

wdrakula пишет:

Сохрани тот код, если не трудно, и опубликуй тут, вместе с версией ИДЕ.

По просьбе wdrakula

Версия IDE 1.8.2

Исходный код

  #include <OneWire.h>
  OneWire  ds(10);
  float temp [3];     // temperature from DS18B20 
  int m=0;            // Number of sensors
  float averageTemp;  //average temperature from sensors DS18B20
  int minTemp=24;        //MIN temperature in the room
  int maxTemp=28;        //MAX temperature in the room
  boolean doorPosition = false; // 0 - close; 1 - open

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

void loop() {
  int n=0;
  float sumTemp = 0;
  scanTemp ();
  
  for (n=0; n<m; n++) {
  sumTemp = sumTemp + temp[n];
  }
  
  averageTemp = sumTemp/m;

  for (n=0; n<m; n++) {
  Serial.print("Temperature from Sensor"); Serial.print(n+1);Serial.print("  ");
  Serial.println(temp[n]);
  }
  
  Serial.print("Average Temperature ");
  Serial.println(averageTemp);
  Serial.print("Number of sensors = ");
  Serial.println(m);
  Serial.print("doorPosition = ");
  Serial.println(doorPosition);
  Serial.println();
    
  if (averageTemp < minTemp) {
    closeDoor();
    }

  if (averageTemp > maxTemp){
    openDoor();
    }
    
  delay (5000);
}

Функция ScanTemp () (собственно в которой ошибка)

void scanTemp (){
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;
  
  while (ds.search(addr)) {
    ds.reset();
    ds.select(addr);
    ds.write(0x44, 1);  
    delay(1000);
    present = ds.reset();
    ds.select(addr);    
    ds.write(0xBE);        
    for ( i = 0; i < 9; i++) {         
    data[i] = ds.read();
    }
    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);
    if (cfg == 0x00) raw = raw & ~7;
    else if (cfg == 0x20) raw = raw & ~3;
    else if (cfg == 0x40) raw = raw & ~1;
    
    }
    celsius = (float)raw / 16.0;
    temp [m] = celsius;
    m=m+1;
  }
  ds.reset_search();  
}

Функция closeDoor ()

void closeDoor () {
  if (doorPosition == true) {
  Serial.println("Door close!");
  Serial.println();
  doorPosition = false;
  }
}  

Функция openDoor ()

void openDoor () {
  if (doorPosition == false) {
  Serial.println("Door open!");
  Serial.println();
  doorPosition=true;
  }
}