Периодически поврежденные данные возвращаются из ESP8266.
У меня есть Arduino Uno, подключенный к ESp8266 через адаптер ESP-01. Адаптер питается от контактов Arduino 5 В и Gnd, а Tx/Rx к адаптеру использует контакты Arduino 2/3. У меня есть базовый код, который устанавливает ESP8266 в качестве точки доступа, и я могу подключиться к точке доступа со своего телефона, отправить сообщение и получить ответ от ESP8266. Это работает нормально в 75% случаев. в других случаях сообщение, полученное ESP8266 (и распечатанное на последовательном мониторе для отладки), усекается и/или повреждается. Я пробовал другой ESp8266 и другой адаптер; Я не получаю ошибок, связанных с повреждением, при использовании других программ, запущенных на Uno; Я снизил скорость связи между Uno и ESp8266 до 9600 бод. В чем может быть причина искажения данных, которое я вижу? Спасибо
Я обновил свое приложение, и данные больше не повреждены, но в возвращенном потоке данных отсутствуют символы.
Вот мой скетч:
#include <SoftwareSerial.h>
//
// Интерфейс ESP8266
/////////////////////
SoftwareSerial wifiSerial(2, 3); // RX, TX для ESP8266
#define TICK 100
bool DEBUG = true;
int responseTime = 1000;
#define ESP8266CMD_SET_UART_9600 "AT+UART_CUR=9600,8,1,0,3"
#define ESP8266CMD_SET_UART_38400 "AT+UART_CUR=38400,8,1,0,0"
#define ESP8266CMD_ECHO_OFF "ATE0"
#define ESP8266CMD_ECHO_ON "ATE1"
#define ESP8266CMD_SET_WIFI_STATION_MODE "AT+CWMODE=1"
#define ESP8266CMD_SET_WIFI_SOFTAP_MODE "AT+CWMODE=2"
#define ESP8266CMD_GET_IP_ADDRESS "AT+CIFSR"
#define ESP8266CMD_CONFIG_AP_LIST_ALL "AT+CWLAPOPT=1,2047" // Сортировка и отображение всех сетей
#define ESP8266CMD_CONFIG_AP_LIST "AT+CWLAPOPT=1,3" // Сортировка и отображение только ECN/ESSID
#define ESP8266CMD_LIST_AVAILABLE_APS "AT+CWLAP"
#define ESP8266CMD_SEND_DATA "AT+CIPSEND=0," // требуемая длина добавляемых данных
#define ESP8266CMD_CLOSE_ALL_CONNECTIONS "AT+CIPCLOSE=5"
//
// ЖК-интерфейс
////////////////
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
//
// НАСТРАИВАТЬ
////////////
void setup()
{
Serial.begin(115200);
Serial.println("Initialising...");
lcd.begin( 16, 2 ); // ЖК-дисплей 16x2
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); // Включаем подсветку
lcd.setBacklight(HIGH);
lcd.home();
lcd.print("Initialising...");
wifiSerial.begin(9600);
sendToWifi( ESP8266CMD_ECHO_OFF, responseTime, DEBUG );
sendToWifi( ESP8266CMD_SET_WIFI_STATION_MODE, responseTime, DEBUG );
sendToWifi( ESP8266CMD_CONFIG_AP_LIST, responseTime, DEBUG );
Serial.println("Wifi connection is running!");
lcd.clear();
lcd.print("Ready");
pinMode(13,OUTPUT); //устанавливаем встроенный светодиод в качестве вывода
}
//
// ПЕТЛЯ
//////////
void loop()
{
String APList = sendToWifi(ESP8266CMD_LIST_AVAILABLE_APS, responseTime, DEBUG);
Serial.println(APList);
delay(100 * TICK);
}
/*
* Name: sendToWifi
* Description: Send data to ESP8266.
* Params: command - the data/command to send
* timeout - the time to wait for a response
* debug - print to Serial window?(true = yes, false = no)
* Returns: Response from the esp8266 (if there is a reponse)
*/
String sendToWifi(String command, const int timeout, boolean debug){
String response = "";
if(debug)
Serial.println( "Command[" + command + "]" );
wifiSerial.println(command); // отправляем строку esp8266
long int time = millis();
while( (time+timeout) > millis())
{
while(wifiSerial.available())
{
char c = wifiSerial.read(); // читаем ответ
response += c;
time = millis(); // данные получены - сброс таймаута
}
}
if(debug)
Serial.println( "Response[" + response + "]" );
return response;
}
..а вот выходные данные отладки из примера.
Initialising...
Command[ATE0]
Response[
OK
]
Command[AT+CWMODE=1]
Response[
OK
]
Command[AT+CWLAPOPT=1,3]
Response[
OK
]
Wifi connection is running!
Command[AT+CWLAP]
Response[]
Command[AT+CWLAP]
Response[+CWLAP:(4,"VM2293456_EXT")
+CWLAP:(3,"NVR9ca3a92708f2")
+CWLA]
+CWLAP:(4,"VM2293456_EXT")
+CWLAP:(3,"NVR9ca3a92708f2")
+CWLA
Command[AT+CWLAP]
Response[+CWLAP:(4,"VM2293456_EXT")
+CWLAP:(4,"VM2293456")
+CWLAP:(5,"]
+CWLAP:(4,"VM2293456_EXT")
+CWLAP:(4,"VM2293456")
+CWLAP:(5,"
Помимо двух сетей VM2293456 и VM2993456_EXT существует ряд других доступных сетей, и при некоторых запусках я вижу именно эти сети. В любом случае в тексте ответа пропущены символы.
@MPH, 👍0
Обсуждение2 ответа
Лучший ответ:
Прошивка AT записывает данные в последовательный порт без какого-либо контроля. Если данные не считываются быстро, последовательный буфер переполняется. Если вы подсчитаете байты, прочитанные вашим скетчем (включая 2 невидимых символа конца строки в каждой строке), вы посчитаете 64 байта. Это размер буфера RX SoftwareSerial. SoftwareSerial может сообщить вам, если буфер переполнен. Вызовите wifiSerial.overflow()
.
CWLAP требуется время для выполнения на стороне esp8266, а затем прошивка AT передает полный список на последовательный порт. Чтение его побайтно и сохранение millis() между ними будет слишком медленным. Вам нужно прочитать его быстрее с буфером.
Я использую readBytesUntil
для чтения строки в буфер. Эта функция ожидает следующего байта, если между байтами есть пробел, и прекращает чтение, если получен терминатор или истекло время ожидания. Тайм-аут по умолчанию составляет 1000 миллис. Его можно установить с помощью setTimeout(t)
.
В вашем скетче вы используете String. Не рекомендую для проекта, но для теста можно использовать:
result += wifiSerial.readStringUntil('\n');
чтобы прочитать и добавить целую строку.
Спасибо, это имеет большой смысл — я изменю свой код и попробую еще раз. Ваше здоровье, @MPH
Итак, теперь я изменил свой фонд получения следующим образом:
`
void readFromWiFi()
{
int l, j = 0;
делать {
l = wifiSerial.readBytesUntil('\0', &Buffer[j], BUFFER_LEN);
j += л;
Буфер[j] = '\0';
} Пока (л > 0);
}
`
.. но я все еще получаю только 64 символа данных. Обратите внимание: я использую «SoftwareSerial», и в этом случае я не понимаю, почему мне доступна функция readBytesUntil(). Где я ошибаюсь?, @MPH
AT-прошивка никогда не отправляет \0. строка заканчивается на \r\n. и читать в буфер readBytesUntil('\n', &Buffer, BUFFER_LEN)
https://arduinoprosto.ru/q/63106/how-to-compare-a-string/63116#63116, @Juraj
@Juraj: вам нужно будет добавить '\n' вручную - result += wifiSerial.readStringUntil('\n') + "\n";
, @SBF
@SBF, нам нужны только данные, @Juraj
Используя информацию, любезно предоставленную мне людьми, я переписал свой код для использования библиотеки AltSoftSerial, и теперь мое небольшое приложение работает нормально. Спасибо. AltSoftSerial использует контакты 8/9 в режиме прерываний, оставляя «стандартные» контакты 1/2 последовательной связи для канала отладки. У меня он работает на скорости 19200 бод. Я удалил переменную String из кода, и моим последним улучшением будет использование malloc() для выделения буфера данных вместо текущего статически объявленного буфера. Цель моего тестового приложения — подключиться к моей домашней сети Wi-Fi и распечатать выделенный IP-адрес. Весь вывод поступает на ЖК-дисплей, но вместо него можно использовать последовательный монитор.
Вот мой код:
#include <AltSoftSerial.h>
#include "ESP8266_cmd.h"
//
// Подключаемся к домашней сети Wi-Fi с помощью AltSoftSerial через контакты 8/9 к ESP8266.
/////////////////////////////////////////////////// /////////////////////////
//
// Интерфейс ESP8266
/////////////////////
AltSoftSerial wifiSerial; // RX, TX для ESP8266
#define TICK 100
#define DEBUG false
#define ResponseTime 1000
#define NW_CREDENTIALS "\"VM2293456\",\"----------\""
//
// ЖК-дисплей определяет
//////////////
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
int n = 1;
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
//
// Буфер для данных ESP8266
//////////////////////////
#define BUFFER_LEN 512
char Buffer[BUFFER_LEN];
//
// Состояние////////////////
enum {
STATE_INIT_WIFI = 0,
STATE_WIFI_CONNECT,
STATE_WAIT_FOR_CONNECTED,
STATE_GET_IP_ADDRESS,
STATE_WAIT,
STATE_ERROR,
} State;
int MachineState = STATE_ERROR;
int ErrorCode = 0;
void setup()
{
String response;
Serial.begin(115200);
Serial.println("Initialising...");
lcd.begin( 16, 2 ); // ЖК-дисплей имеет размер 16x2. Cmd — столбец, строка
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); // Включаем подсветку
lcd.setBacklight(HIGH);
lcd.clear();
lcd.home();
lcd.print( "Network Connect " );
wifiSerial.begin(19200);
MachineState = STATE_INIT_WIFI;
}
void loop()
{
String response;
char cmd[64];
switch( MachineState )
{
case STATE_INIT_WIFI:
lcd.setCursor( 0, 1);
lcd.print("Initialising ");
sendToWifi( ESP8266CMD_ECHO_OFF, ResponseTime, DEBUG );
if( strcmp( Buffer, "OK" ) != 0 )
{
ErrorCode = 1;
MachineState = STATE_ERROR;
break;
}
sendToWifi( ESP8266CMD_SET_WIFI_STATION_MODE, ResponseTime, DEBUG );
if( strcmp( Buffer, "OK" ) != 0 )
{
ErrorCode = 2;
MachineState = STATE_ERROR;
break;
}
MachineState = STATE_WIFI_CONNECT;
break;
case STATE_WIFI_CONNECT:
lcd.setCursor( 0, 1);
lcd.print("Connecting ");
strcpy( cmd, ESP8266CMD_CONNECT_TO_AP );
strcat( cmd, NW_CREDENTIALS );
sendToWifi( cmd, ResponseTime, DEBUG );
MachineState = STATE_WAIT_FOR_CONNECTED;
break;
case STATE_WAIT_FOR_CONNECTED:
lcd.setCursor( 0, 1);
lcd.print("Wait for connect");
readFromWiFi( ResponseTime );
if( strstr(Buffer, "WIFI GOT IP") != NULL )
MachineState = STATE_GET_IP_ADDRESS;
else
delay( 1000 );
break;
case STATE_GET_IP_ADDRESS:
lcd.setCursor( 0, 1);
lcd.print("Getting IP Addr ");
sendToWifi(ESP8266CMD_GET_IP_ADDRESS,ResponseTime,DEBUG);
MachineState = STATE_ERROR; // премьер для случая ошибки
ErrorCode = 3;
if( strstr( Buffer, "OK" ) != NULL )
{
if( strncmp( Buffer, "+CIFSR:STAIP", 12 ) == 0 )
{
lcd.setCursor( 0, 1 );
lcd.print( " " );
lcd.setCursor( 0, 1 );
for( int i = 15; i < strlen(Buffer ); i++ )
{
if( Buffer[i] == '"' )
Buffer[i] = '\0';
}
lcd.print( &Buffer[14] ); // Отображение извлеченного IP-адреса
MachineState = STATE_WAIT;
}
}
break;
case STATE_WAIT:
delay(10000);
MachineState = STATE_GET_IP_ADDRESS;
break;
case STATE_ERROR:
default:
lcd.setCursor( 0, 1 );
lcd.print( " " );
lcd.setCursor( 0, 1 );
strcpy( cmd, "Err " );
itoa( ErrorCode, &cmd[strlen(cmd)], 10 );
lcd.print( cmd );
delay(10000);
break;
}
}
/*
* Name: readFromWiFi
* Description: Read data from ESP8266.
* Params: timeout - the time to wait for a response
* debug - print to Serial window?(true = yes, false = no)
* Returns: Response from the esp8266 (if there is a reponse) in Global Buffer
*/
void readFromWiFi(int timeout)
{
int l = 0;
long int t = millis();
while( ( t + timeout ) > millis() ){
while( wifiSerial.available() > 0 ) {
Buffer[l++] = wifiSerial.read();
t = millis();
}
}
Buffer[l] = '\0';
trimRight( Buffer );
trimLeft( Buffer );
}
/*
* Name: sendToWifi
* Description: Function used to send data to ESP8266.
* Params: command - the data/command to send; timeout - the time to wait for a response; debug - print to Serial window?(true = yes, false = no)
* Returns: The response from the esp8266 (if there is a reponse)
*/
void sendToWifi( const char *command, const int timeout, boolean debug){
if(debug)
{
Serial.print( "Command[" );
Serial.print( command );
Serial.println( "]" );
}
wifiSerial.println( command ); // отправляем строку esp8266
readFromWiFi( timeout);
if(debug)
{
Serial.print( "Response[" );
Serial.print( Buffer );
Serial.println( "]" );
}
}
void trimRight( char *src )
{
int i = strlen(src)-1;
for( ; i >= 0; i-- )
{
if( (src[i] != ' ' ) && ( src[i] != '\t' ) && ( src[i] != '\n' ) )
break;
}
src[i] = '\0';
}
void trimLeft( char *src )
{
int i, l = strlen(src);
for( i = 0; i < l; i++ )
{
if( (src[i] != ' ' ) && ( src[i] != '\t' ) && ( src[i] != '\n' ) && ( src[i] != '\r' ) )
break;
}
memmove( src, &src[i], l);
}
а вот заголовочный файл ESP822_cmd.h, который я создал:
// ESP82266_cmd.h
//
// #defines для интерфейса ESP8266
//
#define ESP8266CMD_SET_UART_9600 "AT+UART_DEF=9600,8,1,0,0"
#define ESP8266CMD_SET_UART_19200 "AT+UART_DEF=19200,8,1,0,0"
#define ESP8266CMD_SET_UART_38400 "AT+UART_CUR=38400,8,1,0,0"
#define ESP8266CMD_ECHO_OFF "ATE0"
#define ESP8266CMD_ECHO_ON "ATE1"
#define ESP8266CMD_SET_WIFI_STATION_MODE "AT+CWMODE=1"
#define ESP8266CMD_SET_WIFI_SOFTAP_MODE "AT+CWMODE=2"
#define ESP8266CMD_GET_IP_ADDRESS "AT+CIFSR"
#define ESP8266CMD_CONFIG_AP_LIST_ALL "AT+CWLAPOPT=1,2047" // Сортировка и отображение всех сетей
#define ESP8266CMD_CONFIG_AP_LIST "AT+CWLAPOPT=1,3" // Сортировка и отображение только ECN/ESSID
#define ESP8266CMD_LIST_AVAILABLE_APS "AT+CWLAP"
#define ESP8266CMD_SEND_DATA "AT+CIPSEND=0," // требуемая длина добавляемых данных
#define ESP8266CMD_CLOSE_ALL_CONNECTIONS "AT+CIPCLOSE=5"
#define ESP8266CMD_CONNECT_TO_AP "AT+CWJAP_CUR=" // требуется добавить essid и пароль
```
- AT-команда не отвечает на последовательный монитор
- Отправка данных Arduino в MySQL с помощью phpMyAdmin и XAMPP на Windows10
- Arduino выводит значения мусора на serial monitor с ESP8266
- ошибка: espcomm_upload_mem failed при загрузке скетча
- фатальная ошибка ESP8266WiFi.h: Такого файла или каталога нет
- Как подключить Wi-Fi Shield ESP-12E-ESP8266-UART-WIFI-Wireless-Shield к Arduino
- Получить данные с сайта с помощью ESP8266 с помощью AT-команд
- Захват изображений с OV7670 (без FIFO) с использованием Arduino Uno?
у тебя АТ прошивка в esp-01? Какова длина сообщения и как его прочитать? покажи свой эскиз., @Juraj
Спасибо, что вернулись ко мне. У меня есть прошивка в esp, и я рад поделиться своим эскизом, но, как новичок, я не вижу, как поделиться кодом., @MPH
Я добавил к своему вопросу эскиз и образец выходных данных. Спасибо, @MPH
ESP-01 — это устройство с напряжением 3,3 В., @JRobert
Спасибо, Роберт. Я полагаю, что адаптер, который я использую, понижает напряжение с 5 В до 3,3 В., @MPH