Ответы AT команды (понимание порядка выполнения кода на Arduino)
Я посылаю AT-команды на ESP8266 из Arduino Uno/Nano (ATmega328) и пытаюсь проанализировать конец полученных строк в ответ, чтобы определить, как ESP отреагировал и был ли он успешным (и готов ли он к получению другой команды). еще). Мне известно, что разбор ответов AT-команд уже обсуждался здесь: Получить AT-ответ команд
Но у меня есть конкретная проблема, которая там не освещена, и которая может быть интересна другим людям здесь...
Сначала вызывается функция, которая отправляет AT-команду в ESP для подключения к ThingSpeak (серверу регистрации данных). Это работает нормально в ручном режиме, а также подключается при попытке разобрать ответ, но он анализирует только первую строку, которая возвращается. Например, ожидаемый вывод в последовательном мониторе будет:
c
AT+CIPSTART="TCP","api.thingspeak.com",80
CONNECT
OK
Connected to ThingSpeak!
куда c
это просто командный символ, который я печатаю, чтобы инициировать соединение.
Фактический ответ, однако, заключается в следующем:
c
AT+CIPSTART="TCP","api.thingspeak.com",80
Cannot connect to ThingSpeak!
CONNECT
OK
Это означает, что функция синтаксического анализа завершается до того, как она получает ответ... Как показано в приведенном ниже коде, в настоящее время указан 10-секундный тайм-аут. Даже с 20-секундным таймаутом происходит то же самое, несмотря на тот факт, что при выполнении вручную ответ приходит примерно за одну секунду.
Просто чтобы проверить функцию разбора, я попытался найти "80"
и он вернул истину, так как он находится в конце первой строки ответа. Ищет ли он "OK"
или же "OK\r\n"
результат тот же, он возвращает ложь, а затем остальная часть ответа получена.
Вот код:
boolean waitForResponse(String target, unsigned long timeout)
{
unsigned long startTime = millis();
String responseBuffer;
char charIn;
//keep checking for ESP response until timeout expires
while ((millis() - startTime) < timeout)
{
if (ESP.available())
{
responseBuffer += ESP.read();
}
}
Serial.println(responseBuffer);
if (responseBuffer.endsWith(target))
{
return true;
} else {
return false;
}
}
void openCxn()
{
ESP.print("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80");
delay(500);
if (waitForResponse("80",10000L))
{
Serial.println("Connected to ThingSpeak!");
} else {
Serial.println("Cannot connect to ThingSpeak!");
}
}
Любая идея, почему он возвращается до получения полного ответа (в течение периода ожидания)? Это как-то связано с endsWith()
функционировать?
Следовательно, у вас есть какие-либо идеи о том, как заставить его анализировать весь ответ, а не только первую строку?
Повторюсь, меня интересует только конец ответа (например, "OK"
или же "OK\r\n"
).
2 ответа
Любая идея, почему он возвращается до получения полного ответа (в течение периода ожидания)?
Да, ваша главная проблема заключается в следующем
if (ESP.available())
Это заставляет функцию waitForResponse возвращаться всякий раз, когда UART (или какой-либо другой буфер последовательного ввода-вывода) пуст - это не то, что вам нужно. То, что вы хотите, это читать с последовательного порта, пока вы не получили строку, оканчивающуюся на "\r\n"
,
Это как-то связано с функцией endWith()?
Да, это дополнительная проблема в сочетании с ESP.available
потому что вы пытаетесь сопоставить конец строки ответа от модема с тем, что происходит случайное прерывание данных в последовательном пути. Если вам очень повезло, это будет на линии границ, но, скорее всего, нет, и вы не должны полагаться на это.
Это общая проблема протокола, известная как кадрирование, которая применяется к любому виду асинхронной последовательной связи. Для модемной связи обрамляющие символы \r
а также \n
,
Сделайте себе одолжение и осуществите readline
функция, которая читает один за другим символ, пока предыдущий символ не был \r
и текущий символ \n
и затем верните все, что прочитано до сих пор.
Затем используйте эту функцию исключительно 1 для чтения данных ответа модема. Это относится как к промежуточным кодам результатов, таким как CONNECT
а также коды конечного результата (например, OK
так далее).
"Разбор" строк ответа может быть таким простым, как
if (responseLine.equals("CONNECT\r\n")) ...
или же
if (isFinalResultCode(responseLine)) ...
Как я уже говорил, единственный правильный способ обработки выходных данных модема - это разделить выходные данные на целые строки и выполнить итерацию по одной полной строке за раз.
1 Единственное исключение - при анализе данных ответа AT+CMGS.
Ваше if через некоторое время действительно неверно, потому что вы, возможно, прочитали больше материала назад, и, таким образом, вы не заканчиваете целевую строку, даже если все в порядке.
Вы должны просто проверить, заканчивается ли responseBuffer на target и вернуть true только тогда, когда вы получите новый Char в цикле while, а не после. После истечения времени ожидания просто верните false.