• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Решено NODE MCU v3 парсинг ответа SIM800L

Vypra

Member
Нужно выводить ответы на команды SIM800L. Модуль подключен к Node MCU v3 через UART.

Начальный код этого парня. Переделал под UART.
Код:
String _response = "";                               // Переменная для хранения ответа модуля

void setup()
{
  Serial.begin(9600);                                //Скорость сериал порта
  send_Email("5", "HELLO");                          // 1 - количество символов в теле сообщения, 2 - сообщение
}

void loop()
{}

void send_Email(String num, String message)
{
  Serial.println("AT");                                                                   // Отправили AT для настройки скорости обмена данными
 
  sendATCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", true);                               // задаем команду выхода в интернет
  sendATCommand("AT+SAPBR=3,1,\"APN\",\"internet\"", true);                               // настройки APN

// .... дальше код отправки емейл удалил чтоб не перегружать форум.
}



String sendATCommand(String cmd, bool waiting)                                             // Функция отправки комманд модулю
{
  String _resp = "";                                                                       // Переменная для хранения результата
  Serial.println(cmd);                                                                     // Отправляем команду модулю
  if (waiting) {                                                                           // Если необходимо дождаться ответа...
    _resp = waitResponse();                                                                // ... ждем, когда будет передан ответ
    Serial.println(_resp);                                                                 // Дублируем ответ в монитор порта
  }
  return _resp;                                                                            // Возвращаем результат. Пусто, если проблема
}


String waitResponse() // Функция ожидания ответа и возврата полученного результата
{
  String _resp = "";                                                                       // Переменная для хранения результата
  long _timeout = millis() + 10000;                                                        // Переменная для отслеживания таймаута (10 секунд)
  while (!Serial.available() && millis() < _timeout)  {};                                  // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (Serial.available()) {                                                                // Если есть, что считывать...
    _resp = Serial.readString();                                                           // ... считываем и запоминаем
  }
  else {                                                                                   // Если пришел таймаут, то...
    Serial.println("Timeout...");                                                          // ... оповещаем об этом и...
  }
  return _resp;                                                                            // ... возвращаем результат. Пусто, если проблема
}
Скетч компилится.
ECHO mode на SIM800 отключен. Ответ от модуля должен прилетать просто ОК или ERROR, без дублирования команды в порт.
Проблема в том, что если делать через Serial.println(); команды посылаются. Как только выполнение кода доходит до sendATCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", true); - прилетает

Код:
Soft WDT reset

>>>stack>>>

ctx: cont
sp: 3ffffcc0 end: 3fffffc0 offset: 01b0
3ffffe70:  015c58b6 3fffff2c 3ffffee8 402073de
3ffffe80:  3ffe8685 3ffeee58 00000000 00014cec
3ffffe90:  3ffeee58 3ffeee58 3ffffee8 402031e5
3ffffea0:  3fffdad0 3fffff2c 3ffeee58 402070c8
3ffffeb0:  3ffe8685 0000000a 00000000 00000001
3ffffec0:  3ffeee58 3fffff2c 3fffff20 4020329c
3ffffed0:  3ffe86c0 0000000b 3fffff2c 4020735f
3ffffee0:  3ffeec0a 00000001 3ffefb74 0000000f
3ffffef0:  00000000 3ffeeda8 3fffff2c 402073de
3fffff00:  3ffe86c0 00000004 41be6666 3ffeeec4
3fffff10:  3fffdad0 3ffeeda8 3ffeed9c 402037d0
3fffff20:  3ffefb5c 0000000f 00000000 3ffefafc
3fffff30:  0000000f 0000000b 3ffeeda8 32204c6c
3fffff40:  00393130 00000002 3fffff70 3fffff60
3fffff50:  00000008 07262117 5c576c42 00000007
3fffff60:  00000003 3ffe88a6 00000005 3ffffe46
3fffff70:  00000000 3ffffe4a 3fffdad0 3ffeeec4
3fffff80:  3fffdad0 3ffeeda8 3ffeed9c 40203da0
3fffff90:  00000000 00000000 3ffeee90 40203dec
3fffffa0:  3fffdad0 00000000 3ffeee90 40207994
3fffffb0:  feefeffe feefeffe 3ffe8604 401014c9
<<<stack<<<
??)?? ?F
Любая команда через sendATCommand () - Soft WDT reset.
Что ему может не нравиться? Мне крайне нужен парсинг ответов SIM800 и для других нужд, не только для отправки емейл. Этот код я использовал на Ардуине, но только через софтсериал, и все работало.
 
Последнее редактирование:

pvvx

Активный участник сообщества
while (!Serial.available() && millis() < _timeout) { тут вставьте вызов обработки системных процедур замаскированных в тиме-аут ...};
 

Vypra

Member
while (!Serial.available() && millis() < _timeout) { тут вставьте вызов обработки системных процедур замаскированных в тиме-аут ...};
Сейчас в тысячный раз посмотрел эту строчку и вопрос: а зачем в конце строки ";" ? И в оригинале тоже. Кажется мне не нужно. Приду домой, попробую убрать.
 

CodeNameHawk

Moderator
Команда форума
Сейчас в тысячный раз посмотрел эту строчку и вопрос: а зачем в конце строки ";"
Если просто, то ; нужно для того, что бы ничего не делать(просто ждать символов или истечения времени, не выполняя других команд)правда у вас знак ; не нужен, так есть {}.
Можете выкинуть или {} или ;
В этом и проблема, если импульсов нет, вы повисаете на 10 сек, а есп этого не любит.
Самое простое разбейте 10 секундную задержку на десять задержек по секунде delay(1000);
delay разрешает обрабатывать WiFi и перезагрузки (по WatchDog) не будет.
 

Vypra

Member
В этом и проблема, если импульсов нет, вы повисаете на 10 сек, а есп этого не любит.
Самое простое разбейте 10 секундную задержку на десять задержек по секунде delay(1000);
delay разрешает обрабатывать WiFi и перезагрузки (по WatchDog) не будет.
Ого. Так это косяк не в коде, это проблема глобального масштаба с while на ESP.
Вчера просидел весь вечер с этим. Перепробовал разных вариантов тысячу, курил тему в нете. Пишут вариант добавлять в while цикл delayMicroseconds(1). Не работает. А если выбросить while - все крутится. Делал даже так:
Код:
  while (!Serial.available() )                                  
  {
    yield(); // или Delay (1) или delayMicroseconds(1) не работают
if ((millis() < _timeout ))
   { Serial.println("Timeout...");
   break;
  }
  }
Вопрос открыт: как обойти while? Мне нужно ждать ответа в Serial или пока не пройдет Timeout. Если использовать Delay () на 10 сек, код не будет мониторить Serial.
 

CodeNameHawk

Moderator
Команда форума
Вопрос открыт: как обойти while?
Так я вам уже дал рекомендацию, как обойти.
Код:
uint8_t popytka = 0;
uint8_t prishli_dannyje=0;
do
  delay(1000);
  popytka+=1;
  if (Serial.available())
 {                                                                // Если есть, что считывать...
    _resp = Serial.readString();                                                           // ... считываем и запоминаем
      prishli_dannyje=1;
  }

while ((prishli_dannyje != 1)&&(popytka < 10)) ;                                // Ждем ответа 10 секунд, если пришел ответ или
Но и это не по феншую, ждать данные надо в loop и не используя задержек.
 

Vypra

Member
Точно. Я забыл что есть еще do while ))) Приеду домой, попробую.
Тогда наверное можно так:
Код:
String waitResponse()                                             // Функция ожидания ответа и возврата полученного результата
{
  String _resp = "";                                              // Переменная для хранения результата
  uint8_t timeoff = 0;
  unsigned long _timeout = millis() + 10000;                      // Переменная для отслеживания таймаута (10 секунд)
  do
  { delayMicroseconds(1);                                         // Чем то заняты, чтоб не злить собаку.
    if ((millis() > _timeout ))
    {timeoff = 1;}
  }
  while ((timeoff == 1) || (Serial.available())) ;                    // Крутим do пока не произойдет событие
  timeoff = 0;

  if (Serial.available() )                                       // Если есть, что считывать...
  {
    _resp = Serial.readString();                                 // ... считываем и запоминаем
  }
  else                                                           // Если пришел таймаут, то...
  {
    Serial.println("Timeout...");                                // ... оповещаем об этом и...
    _resp = "Timeout...";
  }

  return _resp;                                                   // ... возвращаем результат. Пусто, если проблема
}
 
Последнее редактирование:

CodeNameHawk

Moderator
Команда форума
Точно. Я забыл что есть еще do while )))
Это вообще ничего не меняет, while тоже выполняет "кучу" операторов, просто мне так удобней писать.
Основная разница do while , что операторы будут выполнены хотя бы один раз.

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

Еще раз повторю, делайте ожидание символов(строки) в основном цикле, без задержек, так как они вам не нужны.
 
Последнее редактирование:

Vypra

Member
Еще раз повторю, делайте ожидание символов(строки) в основном цикле, без задержек, так как они вам не нужны.
Простите, тогда я не понял задумку Вашего кода.
Ну первое не понятно почему после do нет {}, если знаю только так:
do
{
// последовательность операторов
} while (проверка условия);
Как тогда работает последовательность выполнения кода? Когда натыкается на while - возвращается на do ? Допускаю что чего-то не знаю еще. Научите, пожалуйста.
И по поводу задержки - она конечно мне не нужна, но как отсчитать время, если SIM800 сбойнет и ответ не прилетит в Serial? Нужно же выйти с цикла while.
 

Vypra

Member
Ставьте yield() или delay(0), что одно и тоже собственно.
Ставил все. И yield(), и delay(0), и delayMicroseconds (1).
Не сработало.
Здесь с кодом нужно поработать. Сегодня вечерком еще посижу.
 

nikolz

Well-known member
Точно. Я забыл что есть еще do while ))) Приеду домой, попробую.
Тогда наверное можно так:
Код:
String waitResponse()                                             // Функция ожидания ответа и возврата полученного результата
{
  String _resp = "";                                              // Переменная для хранения результата
  uint8_t timeoff = 0;
  unsigned long _timeout = millis() + 10000;                      // Переменная для отслеживания таймаута (10 секунд)
  do
  { delayMicroseconds(1);                                         // Чем то заняты, чтоб не злить собаку.
    if ((millis() > _timeout ))
    {timeoff = 1;}
  }
  while ((timeoff == 1) || (Serial.available())) ;                    // Крутим do пока не произойдет событие
  timeoff = 0;

  if (Serial.available() )                                       // Если есть, что считывать...
  {
    _resp = Serial.readString();                                 // ... считываем и запоминаем
  }
  else                                                           // Если пришел таймаут, то...
  {
    Serial.println("Timeout...");                                // ... оповещаем об этом и...
    _resp = "Timeout...";
  }

  return _resp;                                                   // ... возвращаем результат. Пусто, если проблема
}
гляжу я на это чудо и возникает вопрос к автору.
Вы на каком языке умеете мыслить? На дурине умеете? На Си умеете?
А на русском? Напишите сначала что хотите сделать на русском. И когда будет все вам понятно тогда переводите это со словарем на любой язык программирования.
Это так, ответ на вопрос "научите"
 

Vypra

Member
Это так, ответ на вопрос "научите"
Я попросил человека научить, потому что подумал, что есть какой-то тайный вариант не ставить {} после do. Оказалось это ошибка, которую должен поймать компилятор. А сайт Ардуино я посещаю постоянно, поскольку учусь. )))
Еще раз повторю, делайте ожидание символов(строки) в основном цикле, без задержек, так как они вам не нужны.
Прошу прощения, наверное я не так объяснил задачу или меня не так поняли. Крутить в Loop для меня не вариант. Поскольку код постоянно расширяется и нужно парсить ответ SIM800 под разные задачи (отправка емейл, отправка СМС, качество связи и т.д.) - нужна универсальная функция, после обращения к которой будет возврат результата в разные блоки кода.

Подрезюмирую: благодарочка, друзья.
Сделал так:
Код:
String waitResponse()                                             // Функция ожидания ответа и возврата полученного результата
{
  String _resp = "";                                              // Переменная для хранения результата
  unsigned long _timeout = millis() + 10000;                      // Переменная для отслеживания таймаута (10 секунд)
  do
  { delay(0);

    if (millis() > _timeout )                                     // Условие выхода 1
    {
      Serial.println("Timeout...");
      break;
    }

    if ( Serial.available())                                      // Условие выхода 2
    { _resp = Serial.readString();
      Serial.println(_resp);
      break;
    }
  }
  while (millis() < _timeout + 10) ;                               // Просто событие, которое не наступит никогда

    return _resp;                                                   // ... возвращаем результат. Пусто, если проблема
}
Может код для Гуру покажется "чудом" и нелепым, но так работает, Timeout отсчитывает 10 сек. По событию Serial.available() еще не выходил, потому как еще какие-то проблемы с соединением по UART Sim800 и ответами от модуля. Главное While побороли. )))
 

CodeNameHawk

Moderator
Команда форума
while (millis() < _timeout + 10) ;
замените на while (1) ;
С delay(0) сильно увеличивается вероятность, что можете попасть в ситуацию, когда по сериал получите не всю строку ответа, а только ее часть.
 
Последнее редактирование:

Vypra

Member
С delay(0) сильно увеличивается вероятность, что можете попасть в ситуацию, когда по сериал получите не всю строку ответа, а только ее часть.
Но пока других вариантов не нашлось. Без этого While не работает. Как ждать тогда Timeout и мониторить порт без перехода к отправке следующей команды АТ на Sim800? Через If как-то замутить можно? Альтернатива While?
 
Сверху Снизу