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

Общие вопросы по Arduino IDE для ESP8266

vvzvlad

New member
тогда я все же не пойму между какими двумя командами Вы измеряете время? между отправкой первого и второго символа?
Еще раз. У меня два устройства. Два разных физических устройства. Одно из них - плата с esp8266 и кнопкой. Я одновременно нажимаю кнопку на обоих устройствах, и они одновременно отправляют каждое свой пакет на сервер, на разные порты. Так вот, пакет, отправленный с esp8266 приходит в среднем на 100мс позже пакета, отправленного со второго устройства.
Заранее скажу - я измерял разницу между одновременным нажатием человеком двух кнопок, и она укладывается в 20мс. Т.е. я, одновременно нажимая кнопки, не создаю разницу больше 20мс. Куда-то деваются как минимум 80мс, на которые плата гарантированно медленнее второго устройства отправляет запрос.

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

anakod

Moderator
Команда форума
Для повтора надо вызвать void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state) - иначе следующего прерывания не будет. Аппаратная фигня - сбрасывается и её надо заряжать заново.
Тут по-моему другой код, из Arduino IDE (не очень в курсе что там), но то что в Sming у меня реализовано я проверял, срабатывает несколько раз, сбрасывание бита обработанного прерывания осуществляется регистром, вроде все ОК.
 

tsrman

New member
@vvzvlad
давайте для чистоты экперемента поставим вместо 300 - delay(10) и проверим как-то повлияет это на задержку в 100мс?
еще можно в коде на самом esp выводить время в консоль, что-бы понять сколько на стороне esp занимает выполнение.
 

pvvx

Активный участник сообщества
Тут по-моему другой код, из Arduino IDE (не очень в курсе что там), но то что в Sming у меня реализовано я проверял, срабатывает несколько раз, сбрасывание бита обработанного прерывания осуществляется регистром, вроде все ОК.
GPIO_STATUS_W1TC подтверждается только у назначенных функций - если _gpioInterruptsList != NULL, а если равна? (Т.е. отключили функцию.)
А повторное срабатывание должен управлять пользователь - в функции прерывания вызовом gpio_pin_intr_state_set() или как он пожелает. Но описанное выше - не хорошо - attachInterrupt(x, NULL,xx).
 
Последнее редактирование:

Nikita

New member
Пожалуйста, подскажите, каким образом можно получить объем занятой оперативной памяти, видел, что где-то обсуждали, но повторно найти не могу? В моем sketch'е много строк, периодически встречаются произвольные перезагрузки esp8266.
ets Jan 8 2013,rst cause:4, boot mode:(3,0)

wdt reset
load 0x40100000, len 31264, room 16
tail 0
chksum 0x1f
load 0x3ffe8000, len 2596, room 8
tail 12
chksum 0x47
ho 0 tail 12 room 4
load 0x3ffe8a30, len 3088, room 12
tail 4
chksum 0xe5
csum 0xe5

Не совсем понимаю причину, возможно, в том, что нерационально расходую ОЗУ при работе со строками, хотелось бы найти утечку. Правильно ли я понимаю, что локальные переменные и массивы заведенные в loop() по окончании выполнения каждого цикла освобождают память "самостоятельно"? В частности вопрос про массивы char со строками. Либо же лучше не заморачиваться и пользоваться объектами String?
 

AmatorVic

New member
Пожалуйста, подскажите, каким образом можно получить объем занятой оперативной памяти, видел, что где-то обсуждали, но повторно найти не могу? В моем sketch'е много строк, периодически встречаются произвольные перезагрузки esp8266.
ets Jan 8 2013,rst cause:4, boot mode:(3,0)

wdt reset
load 0x40100000, len 31264, room 16
tail 0
chksum 0x1f
load 0x3ffe8000, len 2596, room 8
tail 12
chksum 0x47
ho 0 tail 12 room 4
load 0x3ffe8a30, len 3088, room 12
tail 4
chksum 0xe5
csum 0xe5

Не совсем понимаю причину, возможно, в том, что нерационально расходую ОЗУ при работе со строками, хотелось бы найти утечку. Правильно ли я понимаю, что локальные переменные и массивы заведенные в loop() по окончании выполнения каждого цикла освобождают память "самостоятельно"? В частности вопрос про массивы char со строками. Либо же лучше не заморачиваться и пользоваться объектами String?
Я пользуюсь String и тоже много текста, и ьтак же иногда вываливается по wdt reset, как у Вас.
Пытался использовать PROGMEM, но не получилось пока
 

bolwoi

New member
Пожалуйста, подскажите, каким образом можно получить объем занятой оперативной памяти, видел, что где-то обсуждали, но повторно найти не могу? В моем sketch'е много строк, периодически встречаются произвольные перезагрузки esp8266.
http://esp8266.ru/forum/threads/obschie-voprosy-po-arduino-ide-dlja-esp8266.224/page-6#post-4764
 

Telek

New member
Nikita, У меня тоже периодически ресетится, с таким же логом. Объем оперативы смотрел - все стабильно. Один из вариантов когда это происходит - не получение ответа от сервера. (GET запрос на сервер проходит, а ответка не получается... причем непонятно, не получается в следствии плохого приема(я через Ёту гоняю), или это какой-то сбой в sdk, который после вытекает в ресет). Причем периодичность разная. Может пол-дня отправлять данные раз в минуту, а может через десяток циклов ребутнутся.
И второй момент, если я сам рестартую модуль вызовом ((void (*)(void))0x40000080)();, то после ресета, модуль рестарует повторно... получается какой-то не правильный вызов ресета...
 

igrr

Moderator
Команда форума
@vvzvlad добавили небольшой фикс, теперь скорость нашего простенького веб-сервера, идущего в комплекте, увеличилась до 900kbps за счет уменьшения задержки отправки пакета (раньше было 100kbps). так что может быть в вашем тесте тоже станет немного лучше.
 

igrr

Moderator
Команда форума
@AmatorVic PROGMEM у нас только для совместимости — расход памяти будет ровно такой же как если вы сделаете просто const char*.
 

igrr

Moderator
Команда форума
В связи ещё с сильными различиями версий HTTP и типов запросов без специализированного сервера HTTP с минимальной, но необходимой функциональностью, работа Arduino как сервера HTTP не возможна. Т.е. её нельзя будет включать в глобальный инет - или помрет или будет лажать...
Согласен — более того, плохо себе представляю, чтобы кто-то включал модуль на esp в инет напрямую, с глобальным IP.
С моей точки зрения, http сервер нужен в основном чтобы задать название точки доступа, к которой модуль должен подключиться.
Если http сервер — важная часть проекта, то лучше добавить $5 к стоимости девайса, сделать его на базе какого-нибудь RT5350f и не заниматься ерундой :)
 

pvvx

Активный участник сообщества
Согласен — более того, плохо себе представляю, чтобы кто-то включал модуль на esp в инет напрямую, с глобальным IP.
С моей точки зрения, http сервер нужен в основном чтобы задать название точки доступа, к которой модуль должен подключиться.
Если http сервер — важная часть проекта, то лучше добавить $5 к стоимости девайса, сделать его на базе какого-нибудь RT5350f и не заниматься ерундой :)
Тоже самое и с запросами к модулю и от него по HTTP - без специальной реализации ничего хорошего не выйдет. Необходимы полные разборки заголовков HTTP и организации ответов.
Web уже работает у меня в проекте "свалки" и сидит напрямую в глобальной сети уже месяцы по фиксированному IP. Ничего его пока из сети не убивает и он не лажает, т.к. реализован специально для этого и никаких +$ не требует. Но написан кое как и требует пересмотра на более понятное описание в коде СИ или C++, т.к. я не программист - больше аппаратура и её связь с софт + обвязка и нахождение простого пути решения задач...
Перезагрузок и прочих зависаний нет, если всё описано правильно. Тем более WDT и прочее уже доступно в SDK в альтернативных исходниках и организуется любой уровень "защиты" от зависаний. В теущей SDK 1.0.1, при отрезании никчемных "obj" из либ Espressif, довольствуясь минимумом Lwip + WiFi (остальное своё) имеется беда только в LIGHT режиме sleep-а WiFi. И то она не приводит к зависаниям и перезагрузкам, а просто теряет TCP соединение. Ну не включать её и модуль будет здоров всегда и не зависнет и не перезагрузится. Остальные "бажки" SDK успешно обходятся, надо только их знать :)

Для главной темы модуля – малопотребляющего режима засыпания и просыпания с опросом датчиков ничего вообще в Arduino IDE не сделано. Данная задача решается специальным загрузчиком, которого в Arduino IDE нет. Уже проверено, что требуется другой загрузчик, состоящий из одного сегмента и тогда время от просыпания до опроса датчиков с включенным "кешированием" flash составляет 30 ms. По опросу программа должна определять – включать или нет далее модуль WiFi для передачи данных или засыпать далее. Ничего этого в Arduino IDE пока не сделано, а идет навязывание использования кривых методов реализации функционала модуля от Espressif. + Пока не проинициализирована SDK Espressif, после спец загрузчика, у нас в наличии 112 килобайт памяти RAM.
Другая задача модуля, как шлюза WiFi к стороннему устройству тоже не реализована.
 
Последнее редактирование:

igrr

Moderator
Команда форума
Для главной темы модуля – малопотребляющего режима засыпания и просыпания с опросом датчиков ничего вообще в Arduino IDE не сделано
Другая задача модуля, как шлюза WiFi к стороннему устройству тоже не реализована.
В моем понимании, Arduino — среда для того чтобы быстро сляпать прототип на коленке. Я не уверен, что кто-то всерьез будет писать код для продукта с использованием Arduino. Главное чтобы можно было за 10 минут подключить пару датчиков, поморгать светодиодом, и отправить/принять HTTP запрос. Если подобный "проект" перерастет стадию протоипа (а это происходит редко), и человек перерастет возможности Arduino, то он может начать ближе знакомиться с железом, начать писать эффективный код, экономить батарейку, выпиливать ненужное из памяти, и т.д.
Делать все это за пользователя, если ему нужно мигать светодиодом, я считаю преждевременной оптимизацией.
Поймите правильно — я не отказываюсь от работы над этими фичами, просто они довольно низко стоят в списке того, что я собираюсь сделать.
 

igrr

Moderator
Команда форума
arduino и nodemcu ориентированы примерно на одну и ту же публику, и у них есть свои достоинства и недостатки (например, ардуино нужно ставить, а в nodemcu память быстро заканчивается). впрочем про установку IDE — эта проблема в ближайшие пару недель решится, т.к. в 1.6.4 есть board manager, через который можно будет устанавливать и обновлять файлы для поддержки esp8266.
 

igrr

Moderator
Команда форума
Кстати, поддержка SD у нас теперь тоже есть :)
 

Telek

New member
igrr, я выше на пару страниц писал - есть проблема: использую wificlient, отправляю телеметрию на сервер. При неполучении ответа от сервера(на сервер данные приходят, а esp ответ не получает ответ на GET запрос... ) происходит или перезагрузка модуля, или утечка памяти(утечка небольшая 150-200байт).

Код:
extern "C" {
#include "user_interface.h"
}

#include <Wire.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <Adafruit_BMP085.h>


#define WIFI_CONNECTION_LIMIT 90
#define SERVER_REQ_DELAY 500
#define SERVER_REQ_WAITING 120
#define MAIN_LOOP_DELAY 1000
#define MAIN_LOOP_DELAY_CNT 900
#define RAIN_COUNTER_PIN 12
#define LED_PIN 13
#define ADC_PARAM 11.0


extern "C" void wdt_feed (void);
extern "C" int readvdd33(void);


const char* ssid     = "";
const char* password = "";
const char* host = "184.106.153.149";
const char* writeKey = "";
const char* writeKey2 = "";

int isRebooted = 0;
int isWiFiDisconnected = 0;
int HostConnectionFailedCount = 0;
float Temperature=0;
long Pressure = 0;


volatile int RainCounter = 0;
volatile long LastMs;
float vcc=0;


volatile int wtdCounter = 0;
volatile int wtdFlag = 0;
int ccnt = 0;

Ticker flipper;

Adafruit_BMP085 dps = Adafruit_BMP085();

void setup() {
 
  // Настройка датчика дожня
  pinMode(RAIN_COUNTER_PIN, INPUT_PULLUP);
  delay(100);
  attachInterrupt(RAIN_COUNTER_PIN, rain_isr_down_up, CHANGE);

  // Светодиод
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  flipper.attach(0.3, flip);

  isRebooted = 1;

  Serial.begin(115200);

  Wire.pins(0, 2);
  Wire.begin();

  Serial.println("Starting...");

  delay(1000);
  dps.begin();

  //WiFi
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
 
  WiFiClient client;

  ccnt++;

  int WiFiConnectionCount = 0;

  wtdFlag = 0;

  // Вычисление температуры и давления
  Pressure=dps.readPressure();
  Temperature=dps.readTemperature();

  Serial.print("Pressure(mm Hg):");
  Serial.print(Pressure / 133.3);    //Выводим давление в мм.рт ст
  Serial.print("Temp:");
  Serial.println(Temperature);
 
  //Передача данных
  if (WiFi.status() != WL_CONNECTED)
  {
    isWiFiDisconnected = 1;

    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
      delay(1000);
      Serial.print(".");

      WiFiConnectionCount++;
      if (WiFiConnectionCount > WIFI_CONNECTION_LIMIT) {
        WiFiConnectionCount = 0;

        Serial.println();
        Serial.println("WiFi connection limit");
        WiFi.disconnect();
        return;
      }

    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());

    delay(500);
  }


  // Устанавливаем соединение с хостом
  Serial.print("connecting to ");
  Serial.println(host);
  delay(2000);
  const int httpPort = 80;

  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    HostConnectionFailedCount++;
    return;
  }

  // Собираем GET запрос
  String url = "GET /update?key=";
  url += writeKey;
  url += "&field1=";
  url += Pressure / 133.3;
  url += "&field2=";
  url += Temperature;
  url += "&field3=";
  url += isRebooted;
  url += "&field4=";
  url += isWiFiDisconnected;
  url += "&field5=";
  url += HostConnectionFailedCount;
  url += "&field6=";
  url += system_get_free_heap_size();
  url += "&field7=";
  url += RainCounter;

  //RainCounter=0;

  Serial.print("Requesting URL: ");
  Serial.println(url);

  // This will send the request to the server
  client.print(url + "\r\n");

  Serial.println(ccnt);

  Serial.print("Wait");
  int wait_cnt = 0;

  while ((!client.available()) && (wait_cnt < SERVER_REQ_WAITING)) {
    Serial.print(".");
    wait_cnt++;
    delay(SERVER_REQ_DELAY);
    wtdFlag = 0;
  }
  Serial.println();
  if (wait_cnt >= SERVER_REQ_WAITING) {
    Serial.println("wait_cnt " + String(SERVER_REQ_WAITING));

  }

  while (client.available()) {
    Serial.print("-");
    String line = client.readStringUntil('\r');
    Serial.print(line);

  }

  client.stop();

  Serial.println();
  Serial.println("closing connection");

  isRebooted = 0;
  isWiFiDisconnected = 0;
  HostConnectionFailedCount = 0;

  Serial.print("RAIN_COUNTER: ");
  Serial.println(RainCounter);

  Serial.print("LastMs: ");
  Serial.println(LastMs);

  Serial.println(system_get_free_heap_size());
 
  vcc=analogRead(17);
  Serial.print("VCC: ");
  Serial.println(vcc);
  Serial.println(readvdd33());
 
  WiFi.disconnect();
 
  int delay_cnt=0;
  while (delay_cnt<MAIN_LOOP_DELAY_CNT){
    wtdFlag = 0;
    delay(MAIN_LOOP_DELAY);
    delay_cnt++;
    Serial.print(".");
  }
  //delay(2000);
}


void flip()
{
  int state = digitalRead(LED_PIN);
  digitalWrite(LED_PIN, !state);

  if (wtdFlag)
  {
    wtdCounter++;
  }
  else
  {
    wtdCounter = 0;
  };

  if (wtdCounter > 500)
  {
    ((void (*)(void))0x40000080)();
  };

  wtdFlag = 1;

}



void rain_isr_down_up(void)
{
  int dMs;
 
  ETS_GPIO_INTR_DISABLE();
 
  long ms = millis();

  dMs=ms - LastMs;
 
  if ((dMs > 10) && (dMs< 500))
  {
    RainCounter++;
  }
 
  LastMs = ms;
 
  ETS_GPIO_INTR_ENABLE();
}
 
Последнее редактирование:

igrr

Moderator
Команда форума
@Telek сорри, не нашел — можете код показать? Сейчас как раз разбираю пачку багов в сетевой части.

Edit: вижу, спасибо

Но я не против любых решений.
Чем бы дитя не тешился, лишь бы не плакал.
Отлично! Спасибо :)
 
Последнее редактирование:

Telek

New member
igrr, Код я приложил. Если делать WiFi.disconnect после каждой отправки, то при неполучении ответа будет утечка. Если не отключаться от точки - то перезагрузка.
PS. "неполучением ответа" я называю ситуацию, когда client.available() за определенное время (до 45 сек жду) не становится больше нуля(у меня в коде есть цикл ожидания).
 
Сверху Снизу