• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Зависает основной цикл

mitgo

New member
Здравствуйте коллеги!
Прошу помощи. Делаю узел автоматизации совмещенного санузла (свет, вытяжка, теплый пол, бойлер ....). В общем проект состоит из нескольких кусков (Arduino IDE). Все работало на столе, но установив устройство на рабочее место, заметил очень неприятный глюк после нескольих срабатываний внешних прерываний (по пину) вешается устройство, но по wifi продолжает пинговаться.
Думал косяк где-то в коде - убрал все, оставил обработчик прерывания и подключение к wifi - глюк остался. В обработчике прерывания ничего сверхъестественного - сравниваем состояние пина и в зависимости от состояния выполняем запись в сдвиговый регистр того или иного значения.
Для поиска глюка решил выводить в Serial смену состояний пина. Дак вот при этом устройство стало зависать значительно позже (ране в районе 10го срабатывания прерывания) - при условии вывода в Serial - зависает где-то на 50-70м прерывании...

Никто не сталкивался с подобной проблемой?
 

mitgo

New member
Приведу код, который "обрезан" и так же не работает
Код:
#define DOOR            15
#define HC_CS           16         //чипселект 74hc959
#define LAMP            6

#include <SPI.h>   


                byte hc74 = 1;
                byte lasthc74 = 1;

int             cfg_doorTime=10; //из конфига должно браться
                byte doorState;
                bool inside=0;
                unsigned long doorTimeLastCh;


int             cfg_light=200;
int             cfg_lightPeriod=3;
                int lightNow;
                unsigned long lightTick=0; 

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  SPI.begin();
  pinMode(HC_CS, OUTPUT);
  pinMode(DOOR, INPUT);
  doorState=digitalRead(DOOR);
  doorTimeLastCh=millis();
  attachInterrupt(DOOR, InsideLoop, CHANGE);
   

}

void loop() {
  // put your main code here, to run repeatedly:
  LightLoop();
  //MqttLoop();
  HC74Loop();
}


void InsideLoop() {
  byte nowDoor=butDebounce(DOOR,6);
  if (nowDoor!=doorState) {
    doorState=nowDoor;  
    if (!doorState){
      if (!inside) {inside=1; doorTimeLastCh=millis();}
      else {inside=0;}
    }
    else {
      if (cfg_doorTime*1000<=millis()-doorTimeLastCh and inside) {inside=0;}       
    }
  }
}

void LightLoop() {     
  if (inside) {
    if (lightNow<=cfg_light) { bitSet(hc74,LAMP); Serial.println("on"); }
    else bitClear(hc74,LAMP);
    //bitSet(hc74,FLOR); 
  }
  else {
    bitClear(hc74,LAMP);
    Serial.println("Off");
    //bitClear(hc74,FLOR);
  }
}

void HC74Loop() {
  if (lasthc74!=hc74) {
    lasthc74=hc74;
    writeHC74(hc74);
  }
}
void writeHC74(byte b) {
  digitalWrite(HC_CS, LOW);
  SPI.transfer(b);
  digitalWrite(HC_CS, HIGH);
}


byte butDebounce(int pin, int deb_delay) {
   byte result, i, currState, lastState;
   result = lastState = 0;
   if(digitalRead(pin) != lastState) {
        lastState = digitalRead(pin); // Запоминаем последнее состояние кнопки
        delay(deb_delay); // Делаем задержку
         for(i = 3; i > 0; --i) { // Трижды сравниваем значение кнопки через равные промежутки времени.
               currState = digitalRead(pin);
               if (currState != lastState) { // Если текущее состояние не совпало с прошлым - завершаем все циклы.
                  break;
               }
               delay(deb_delay);
               lastState = currState;
               if(i = 1) {

                    result = digitalRead(pin); // Если трижды значение было одинаково, то возвращаем его в качестве значения функции
               }
         }
   }
   return result;
}
 

nikolz

Well-known member
Здравствуйте коллеги!
Прошу помощи. Делаю узел автоматизации совмещенного санузла (свет, вытяжка, теплый пол, бойлер ....). В общем проект состоит из нескольких кусков (Arduino IDE). Все работало на столе, но установив устройство на рабочее место, заметил очень неприятный глюк после нескольих срабатываний внешних прерываний (по пину) вешается устройство, но по wifi продолжает пинговаться.
Думал косяк где-то в коде - убрал все, оставил обработчик прерывания и подключение к wifi - глюк остался. В обработчике прерывания ничего сверхъестественного - сравниваем состояние пина и в зависимости от состояния выполняем запись в сдвиговый регистр того или иного значения.
Для поиска глюка решил выводить в Serial смену состояний пина. Дак вот при этом устройство стало зависать значительно позже (ране в районе 10го срабатывания прерывания) - при условии вывода в Serial - зависает где-то на 50-70м прерывании...

Никто не сталкивался с подобной проблемой?
Предположу что вы не запрещаете прерывания когда обрабатываете очередное в колбеке
в итоге будет зависать
 

CodeNameHawk

Moderator
Команда форума
Попробуйте в прерывании только устанавливать флаг, а всю обработку и сброс флага перенести в основной цикл.
 

mitgo

New member
Предположу что вы не запрещаете прерывания когда обрабатываете очередное в колбеке
в итоге будет зависать
Попробовал запрещать прерывания - эффекта не дало, попробовал ставить флаг прерывания и проверять его, в "обрезанном" примере вроде помогло (устал вызывать прерывание), перенес флаг прерывания в рабочий проект - не сразу, но контроллер подвис...
 

mitgo

New member
Предположу что вы не запрещаете прерывания когда обрабатываете очередное в колбеке
в итоге будет зависать
Попробовал запрещать прерывания - эффекта не дало, попробовал ставить флаг прерывания и проверять его, в "обрезанном" примере вроде помогло (устал вызывать прерывание), перенес флаг прерывания в рабочий проект - не сразу, но контроллер подвис...
 

CodeNameHawk

Moderator
Команда форума
перенес флаг прерывания в рабочий проект - не сразу, но контроллер подвис...
Просто может быть не одна проблема.
Посмотрите насчет утечек памяти.
Посмотрите источник перезагрузки в логе.
Если есть обращение к WiFi, то надо каждый раз проверять наличие соединения с "роутером".
Питание и согласование уровней на выводах.
 

nikolz

Well-known member
сделайте все на ESP8266
и напишите на СИ будет и просто и надежно работать
 

=AK=

New member
Все работало на столе, но установив устройство на рабочее место, заметил очень неприятный глюк после нескольих срабатываний внешних прерываний (по пину) вешается устройство, но по wifi продолжает пинговаться.
Почитайте вот эту статью. Если на столе работало, а в реальной обстановке глючит, это скорей всего внешние помехи.
 

mitgo

New member
Просто может быть не одна проблема.
Посмотрите насчет утечек памяти.
Просьба направить по поводу утечек памяти.... (я новичек в программировании железа)
Посмотрите источник перезагрузки в логе.
В том то и дело, что модуль не перезагружается, а просто зависает, причем продолжает пинговаться...
Если есть обращение к WiFi, то надо каждый раз проверять наличие соединения с "роутером".
После зависания контроллер не выполняет ни одной операции в loop(). Поэтому проверить связь с роутером невозможно. Да и смысла в этом не вижу
Питание и согласование уровней на выводах.
Питается модуль от AC-DC преобразователя - 5 V, 700 mA. Далее стоит AMS1117. От 3.3 питается только ESP, все остальное (релюшки, 74hc595, ULN20003) - от 5.
 

CodeNameHawk

Moderator
Команда форума
Просьба направить по поводу утечек памяти....
"ESP.getFreeHeap() returns the free heap size." Проще всего выводить, через сериал.
Тут много полезного.
Libraries — ESP8266 Arduino Core documentation

В ардуиноиде есть возможность включить отладку
ESP8266WiFi library — ESP8266 Arduino Core documentation

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

MakPol

Member
Доброго времени суток

если не сложно, пните в нужную сторону, сделал что-то типа вот такого
Wi-Fi WebServer на WeMos D1 R2
но....
зависает если постоянно не тыкается кто-нибудь к этому модулю. При этом пингуется, но кажись дальше

Код:
void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
...
не уходит

Если постоянно ломиться - может и неделю проработать, но вот как то не понятно мне почему так не стабильно. Там версии две и с client.stop(); как то менее стабильно работает
 

MakPol

Member
Еще мысль, что вот такое

Код:
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
лишнее и может быть причиной зависания
 
В таких местах, где выход из цикла зависит от внешних факторов, лучше ставить дополнительное условие, обычно это счетчик циклов.
 

nikolz

Well-known member
еще лучше ставить таймер
и в колбеке реагировать на ситуацию
 
Сверху Снизу