Скрыть объявление
На нашем форуме недоступен просмотр изображений для неавторизованных пользователей. Если Вы уже зарегистрированы на нашем форуме, то можете войти. Если у Вас еще нет аккаунта, мы будем рады, если Вы к нам присоединитесь. Зарегистрироваться Вы можете здесь.

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

Тема в разделе "Железные вопросы по esp8266", создана пользователем Vypra, 5 фев 2019.

  1. Vypra

    Vypra Новичок

    Сообщения:
    149
    Симпатии:
    0
    Нужно выводить ответы на команды SIM800L. Модуль подключен к Node MCU v3 через UART.

    Начальный код этого парня. Переделал под UART.
    Код (Text):
    1. String _response = "";                               // Переменная для хранения ответа модуля
    2.  
    3. void setup()
    4. {
    5.   Serial.begin(9600);                                //Скорость сериал порта
    6.   send_Email("5", "HELLO");                          // 1 - количество символов в теле сообщения, 2 - сообщение
    7. }
    8.  
    9. void loop()
    10. {}
    11.  
    12. void send_Email(String num, String message)
    13. {
    14.   Serial.println("AT");                                                                   // Отправили AT для настройки скорости обмена данными
    15.  
    16.   sendATCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", true);                               // задаем команду выхода в интернет
    17.   sendATCommand("AT+SAPBR=3,1,\"APN\",\"internet\"", true);                               // настройки APN
    18.  
    19. // .... дальше код отправки емейл удалил чтоб не перегружать форум.
    20. }
    21.  
    22.  
    23.  
    24. String sendATCommand(String cmd, bool waiting)                                             // Функция отправки комманд модулю
    25. {
    26.   String _resp = "";                                                                       // Переменная для хранения результата
    27.   Serial.println(cmd);                                                                     // Отправляем команду модулю
    28.   if (waiting) {                                                                           // Если необходимо дождаться ответа...
    29.     _resp = waitResponse();                                                                // ... ждем, когда будет передан ответ
    30.     Serial.println(_resp);                                                                 // Дублируем ответ в монитор порта
    31.   }
    32.   return _resp;                                                                            // Возвращаем результат. Пусто, если проблема
    33. }
    34.  
    35.  
    36. String waitResponse() // Функция ожидания ответа и возврата полученного результата
    37. {
    38.   String _resp = "";                                                                       // Переменная для хранения результата
    39.   long _timeout = millis() + 10000;                                                        // Переменная для отслеживания таймаута (10 секунд)
    40.   while (!Serial.available() && millis() < _timeout)  {};                                  // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
    41.   if (Serial.available()) {                                                                // Если есть, что считывать...
    42.     _resp = Serial.readString();                                                           // ... считываем и запоминаем
    43.   }
    44.   else {                                                                                   // Если пришел таймаут, то...
    45.     Serial.println("Timeout...");                                                          // ... оповещаем об этом и...
    46.   }
    47.   return _resp;                                                                            // ... возвращаем результат. Пусто, если проблема
    48. }
    49.  
    Скетч компилится.
    ECHO mode на SIM800 отключен. Ответ от модуля должен прилетать просто ОК или ERROR, без дублирования команды в порт.
    Проблема в том, что если делать через Serial.println(); команды посылаются. Как только выполнение кода доходит до sendATCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", true); - прилетает

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

    pvvx Активный участник сообщества

    Сообщения:
    9.002
    Симпатии:
    1.302
    while (!Serial.available() && millis() < _timeout) { тут вставьте вызов обработки системных процедур замаскированных в тиме-аут ...};
     
  3. Vypra

    Vypra Новичок

    Сообщения:
    149
    Симпатии:
    0
    Сейчас в тысячный раз посмотрел эту строчку и вопрос: а зачем в конце строки ";" ? И в оригинале тоже. Кажется мне не нужно. Приду домой, попробую убрать.
     
  4. CodeNameHawk

    CodeNameHawk Moderator Команда форума

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

    Vypra Новичок

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

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.662
    Симпатии:
    183
    Так я вам уже дал рекомендацию, как обойти.
    Код (Text):
    1.  
    2. uint8_t popytka = 0;
    3. uint8_t prishli_dannyje=0;
    4. do
    5.   delay(1000);
    6.   popytka+=1;
    7.   if (Serial.available())
    8.  {                                                                // Если есть, что считывать...
    9.     _resp = Serial.readString();                                                           // ... считываем и запоминаем
    10.       prishli_dannyje=1;
    11.   }
    12.  
    13. while ((prishli_dannyje != 1)&&(popytka < 10)) ;                                // Ждем ответа 10 секунд, если пришел ответ или
    14.  
    Но и это не по феншую, ждать данные надо в loop и не используя задержек.
     
  7. Vypra

    Vypra Новичок

    Сообщения:
    149
    Симпатии:
    0
    Точно. Я забыл что есть еще do while ))) Приеду домой, попробую.
    Тогда наверное можно так:
    Код (Text):
    1. String waitResponse()                                             // Функция ожидания ответа и возврата полученного результата
    2. {
    3.   String _resp = "";                                              // Переменная для хранения результата
    4.   uint8_t timeoff = 0;
    5.   unsigned long _timeout = millis() + 10000;                      // Переменная для отслеживания таймаута (10 секунд)
    6.   do
    7.   { delayMicroseconds(1);                                         // Чем то заняты, чтоб не злить собаку.
    8.     if ((millis() > _timeout ))
    9.     {timeoff = 1;}
    10.   }
    11.   while ((timeoff == 1) || (Serial.available())) ;                    // Крутим do пока не произойдет событие
    12.   timeoff = 0;
    13.  
    14.   if (Serial.available() )                                       // Если есть, что считывать...
    15.   {
    16.     _resp = Serial.readString();                                 // ... считываем и запоминаем
    17.   }
    18.   else                                                           // Если пришел таймаут, то...
    19.   {
    20.     Serial.println("Timeout...");                                // ... оповещаем об этом и...
    21.     _resp = "Timeout...";
    22.   }
    23.  
    24.   return _resp;                                                   // ... возвращаем результат. Пусто, если проблема
    25. }
     
    Последнее редактирование: 6 фев 2019
  8. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.662
    Симпатии:
    183
    Это вообще ничего не меняет, while тоже выполняет "кучу" операторов, просто мне так удобней писать.
    Основная разница do while , что операторы будут выполнены хотя бы один раз.

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

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

    Vypra Новичок

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

    Сергей_Ф Moderator Команда форума

    Сообщения:
    2.205
    Симпатии:
    229
    и не должен.
    Ставьте yield() или delay(0), что одно и тоже собственно.
     
  11. Vypra

    Vypra Новичок

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

    Сергей_Ф Moderator Команда форума

    Сообщения:
    2.205
    Симпатии:
    229
    не спорю. Просто не используйте delayMicroseconds. Это не даст никакого эффекта.
     
  13. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.662
    Симпатии:
    183
  14. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.662
    Симпатии:
    183
    Такие ошибки выловит компилятор.
     
    Последнее редактирование: 6 фев 2019
  15. nikolz

    nikolz Гуру

    Сообщения:
    4.993
    Симпатии:
    458
    гляжу я на это чудо и возникает вопрос к автору.
    Вы на каком языке умеете мыслить? На дурине умеете? На Си умеете?
    А на русском? Напишите сначала что хотите сделать на русском. И когда будет все вам понятно тогда переводите это со словарем на любой язык программирования.
    Это так, ответ на вопрос "научите"
     
  16. Vypra

    Vypra Новичок

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

    Подрезюмирую: благодарочка, друзья.
    Сделал так:
    Код (Text):
    1. String waitResponse()                                             // Функция ожидания ответа и возврата полученного результата
    2. {
    3.   String _resp = "";                                              // Переменная для хранения результата
    4.   unsigned long _timeout = millis() + 10000;                      // Переменная для отслеживания таймаута (10 секунд)
    5.   do
    6.   { delay(0);
    7.  
    8.     if (millis() > _timeout )                                     // Условие выхода 1
    9.     {
    10.       Serial.println("Timeout...");
    11.       break;
    12.     }
    13.  
    14.     if ( Serial.available())                                      // Условие выхода 2
    15.     { _resp = Serial.readString();
    16.       Serial.println(_resp);
    17.       break;
    18.     }
    19.   }
    20.   while (millis() < _timeout + 10) ;                               // Просто событие, которое не наступит никогда
    21.  
    22.     return _resp;                                                   // ... возвращаем результат. Пусто, если проблема
    23. }
    Может код для Гуру покажется "чудом" и нелепым, но так работает, Timeout отсчитывает 10 сек. По событию Serial.available() еще не выходил, потому как еще какие-то проблемы с соединением по UART Sim800 и ответами от модуля. Главное While побороли. )))
     
  17. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.662
    Симпатии:
    183
    замените на while (1) ;
    С delay(0) сильно увеличивается вероятность, что можете попасть в ситуацию, когда по сериал получите не всю строку ответа, а только ее часть.
     
    Последнее редактирование: 7 фев 2019
    Vypra нравится это.
  18. Vypra

    Vypra Новичок

    Сообщения:
    149
    Симпатии:
    0
    Красивее. Спасибо за помощь )))
     
  19. Vypra

    Vypra Новичок

    Сообщения:
    149
    Симпатии:
    0
    Но пока других вариантов не нашлось. Без этого While не работает. Как ждать тогда Timeout и мониторить порт без перехода к отправке следующей команды АТ на Sim800? Через If как-то замутить можно? Альтернатива While?
     
  20. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.662
    Симпатии:
    183
    Прикиньте примерное время ответа и задайте ее. нп. delay(500);
     

Поделиться этой страницей