0

I have an Arduino Uno connected to an ESp8266 via an ESP-01 adapter. The Adapter is powered from the Arduino 5v and Gnd pins and the Tx/Rx to the Adapter use Arduino pins 2/3. I have basic code which sets the ESP8266 as an access point and I am able to connect to the AP from my phone, send a message and receive a reply from the ESP8266. This works fine for 75% of the time. other times, the message received by ESP8266 ( and printed on the serial monitor for debug ) is truncated, and/or corrupted. I have tried a different ESp8266 and a different adapter; I don't get corruption errors with other programs run on the Uno; I have dropped the communications speed between the Uno and ESp8266 to 9600 baud. What could be the cause of the corruption I am seeing in the data ? Thanks

I have updated my app an no longer get corrupted data, but there are characters data missing from the returned data stream.

Here is my sketch :

#include <SoftwareSerial.h>

//
// ESP8266 interface
////////////////////

SoftwareSerial wifiSerial(2, 3);            // RX, TX for 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" // Sort and display all netwroks  
#define ESP8266CMD_CONFIG_AP_LIST           "AT+CWLAPOPT=1,3"    // Sort and display ECN / ESSID only  
#define ESP8266CMD_LIST_AVAILABLE_APS       "AT+CWLAP"

#define ESP8266CMD_SEND_DATA                "AT+CIPSEND=0,"     // required data length to be appended
#define ESP8266CMD_CLOSE_ALL_CONNECTIONS    "AT+CIPCLOSE=5"

//
// LCD interface
////////////////

#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);

//
// S E T U P
////////////

void setup()
{
  Serial.begin(115200);
  Serial.println("Initialising...");

  lcd.begin( 16, 2 );                                 //  LCD is 16x2

  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);        // Switch on the backlight
  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);  //set build in led as output
}

//
// L O O P
//////////

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);       // send string esp8266

 long int time = millis();
 while( (time+timeout) > millis())
 {
   while(wifiSerial.available())
   {
   char c = wifiSerial.read();      // read resonse

    response += c;
    time = millis();                // data received - reset timeout
   }  
 }
 if(debug)
    Serial.println( "Response[" + response + "]" );

 return response;
}

..and here is output debug data from a sample run.

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,"

As well as the two networks VM2293456 and VM2993456_EXT there are a number of other netwroks available, and on some runs I see those networks shown. In any case, there are missing characters from the response text.

  • you have AT firmware in esp-01? how long is the message and how do you read it? show your sketch. – Juraj Apr 4 at 17:50
  • Thanks for coming back to me. I do have firmware in the esp and I'm happy to share my sketch, but as a newbie here I can't see how to share the code. – MPH Apr 10 at 10:16
  • I have added the sketch and sample output data to my question. Thanks – MPH Apr 10 at 10:34
  • ESP-01 is a 3.3v device. – JRobert Apr 10 at 20:25
  • Thanks Robert. I beleive that the adapter I'm using steps 5v down to 3.3v – MPH Apr 10 at 21:50
0

AT firmware writes the data to Serial without any control. If the data are not read fast the Serial buffer overflows. If you count the bytes read by your sketch (including 2 not visible line ending characters per line) you count 64 bytes. That is the size of the RX buffer of SoftwareSerial. SoftwareSerial can tell you if the buffer overflowed. Call wifiSerial.overflow().

The CWLAP takes time to execute on esp8266 side and then the AT firmware puts out the complete listing to Serial. Reading it byte by byte and storing millis() in-between is then too slow. You need to read it faster with a buffer.

I use readBytesUntil to read a line into buffer. This function waits for the next byte if there is a gap between bytes and stops reading if terminator is received or it times out. Default timeout is 1000 millis. It can by set with setTimeout(t).

In your sketch you use String. I do not recommend it for a project, but in a test you could use:

result += wifiSerial.readStringUntil('\n');

to read and append a whole line.

  • Thanks, that makes a lot of sense - I'll modify my code and try again. Cheers – MPH Apr 10 at 21:52
  • So I have now modified my receive fundtion to this : void readFromWiFi() { int l, j = 0; do { l = wifiSerial.readBytesUntil( '\0', &Buffer[j], BUFFER_LEN ); j += l; Buffer[j] = '\0'; } while( l > 0 ); } .. but I am still getting 64 characters of data only. Note I am using 'SoftwareSerial', and in that case I can't see why the readBytesUntil() function is available to me. Where am I going wrong ? – MPH Apr 12 at 18:26
  • AT firmware never sends \0. line ends with \r\n. and to read into buffer readBytesUntil('\n', &Buffer, BUFFER_LEN) arduino.stackexchange.com/questions/63106/… – Juraj Apr 13 at 4:18
1

Taking the information that people have kindly offered to me, I have re-written my code to use the AltSoftSerial library and I now have my small app working fine. Thanks. AltSoftSerial uses pins 8/9 in an interrupt driven manner, leaving the 'standard' pin 1/2 serial comms for a debug channel. I have it running at 19200 baud. I have remove String variable from the code and my final improvement will be to use malloc() to allocation data buffer in place of the current statically declared buffer. The purpose of my test app is to connect to my home wifi network a to print out the IP address allocated. All output goes to an LCD display, but the serial monitor could be used instead.

Here's my code :

#include <AltSoftSerial.h>
#include "ESP8266_cmd.h"

//
// Connect to home WiFi network using AltSoftSerial via pins 8/9 to ESP8266
///////////////////////////////////////////////////////////////////////////


//
// ESP8266 interface
////////////////////

AltSoftSerial wifiSerial;                   // RX, TX for ESP8266

#define TICK  100

#define DEBUG                               false
#define ResponseTime                        1000

#define NW_CREDENTIALS                      "\"VM2293456\",\"----------\""

//
// LCD defines
//////////////

#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);


//
// Buffer for ESP8266 data
//////////////////////////

#define BUFFER_LEN    512
char Buffer[BUFFER_LEN];

//
// State Machine 
////////////////

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 );                                 //  LCD is 16x2.  Cmd is Column, Row

  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);        // Switch on the backlight
  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;   // prime for error case
    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] );   // Display extracted IP address
        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 );       // send string 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); 
}

and here is the ESP822_cmd.h header file that I created :

// ESP82266_cmd.h
//
// #defines for ESP8266 interface
//


#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" // Sort and display all netwroks  
#define ESP8266CMD_CONFIG_AP_LIST           "AT+CWLAPOPT=1,3"    // Sort and display ECN / ESSID only  
#define ESP8266CMD_LIST_AVAILABLE_APS       "AT+CWLAP"

#define ESP8266CMD_SEND_DATA                "AT+CIPSEND=0,"      // required data length to be appended
#define ESP8266CMD_CLOSE_ALL_CONNECTIONS    "AT+CIPCLOSE=5"

#define ESP8266CMD_CONNECT_TO_AP            "AT+CWJAP_CUR="      // required essid and password to be appended
```

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.