Basic operations on an ESP8266 wifi module from Arduino

Basic operations on an ESP8266 wifi module from Arduino

Basic operations on an ESP8266 wifi module from Arduino

When Espressif launched the first modules on the market Wireless with the integrated ESP8266 and firmware with which to handle it using AT commands, what we users were interested in was integrating it into assemblies with microcontrollers and the problems were reduced to knowing the (formerly) dark ESP8266 AT command table, feeding needs or ESP8266 firmware update.

Table of Contents

    Then alternatives quickly arrived to program the ESP8266 and module implementations Wireless of very different formats that raised other concerns: which ESP8266 wifi module to choose depending on the range of the different antennas (including external ones) or the physical integration of these new modules in our assemblies.

    Surely, due to all these changes, emphasis may not have been placed on the most basic aspects, the most basic management of the ESP8266 wifi module. Although polarity.es You can find information on the use of the ESP8266 and there are some applications intended to explain in a generic way the operation of the ESP8266 wifi module using AT commands, especially in the article on library to make HTTP queries from Arduino with the ESP8266 wifi module, readers' impressions suggest that it would be useful to add some more basic information to help users of the ESP8266 to carry out their own implementations.

    Discuss the basic operations to work with the ESP8266 and proposing generic solutions is an objective of several very different parts; To help follow the content of the article, the following index can serve as a guide:

    Control the ESP8266 wifi module from the computer through the serial port

    From a plate Arduino and using your IDE it is possible to monitor the operation of a ESP8266 wifi module, send the ESP8266 AT commands and see the answer but it is much more convenient to do it from a computer with a terminal type application.

    Using CuteCom to test the ESP8266 wifi module through the serial port

    Depending on which board Arduino used, only one hardware serial port may be available, which adds a little inconvenience to sending and receiving. Changing the communications speed is much more comfortable in a serial communications application from a computer and some motherboards. Arduino (and in some circumstances) do not support the higher speeds of serial communications well, especially 115200 baud, which is the default speed of the latest versions of the firmware.

    About What program to use to monitor the ESP8266 using the serial port, there are many to choose from according to needs and preferences; lately I'm using the classic more CuteCom (the one in the screenshot above) because it is very comfortable for me to repeat certain ESP8266 wifi module AT orders in project testing.

    Some recommendations have already been given here on programs that function as a serial console; For example, when talking about PuTTY for controlling UART serial devices from the computer. PuTTYIn addition to being an excellent application, it is available for most desktop operating systems. Furthermore, as PuTTY can be used to act as a console with both the serial port and the Internet protocol family (TCP/IP), including those that operate on TLS, becomes a common tool that more than repays the (little) time spent configuring it and getting used to its use.

    Using PuTTY to test the ESP8266 wifi module through the serial port

    In addition to serial communications software, to connect the ESP8266 wifi module to the port USB A computer also requires a converter USB to series TTL. As in the case of software, there are several versions, from which they are only used to convert the port USB on a serial port TTL (which can be obtained from one Euro) to those that can emulate different protocols (such as SPI o I2C).

    Just like a program that functions as a serial console, the hardware to communicate the computer via USB with a logic circuit (not just the ESP8266) will be a common tool in the work of a microcontrolled application developer, it is worth having it in the toolbox as soon as possible and working with it ESP8266 wifi module It is an excellent opportunity to get one.

    Hardware for USB UART serial communications to monitor the ESP8266 wifi module

    The converter USB a UART TTL It can also be used to monitor the behavior of a circuit that uses the ESP8266, to do this, the outputs that you want to monitor are connected in series to the data input (RX) of the converter with a fast diode (the 1N4148, for example) and a resistor (2K2, for example) in parallel with each other. Such a setup works like a hardware serial sniffer.

    Sniffer example for ESP8266 connected to Arduino using a USB UART TTL converter

    Although the sniffer in the image above is certainly rudimentary (among other things it does not have buffer) is sufficient to monitor the operation of an assembly with Arduino and ESP8266.

    Removing the sniffer from the previous scheme, the schematic showing how to connect a ESP8266 wifi module to a plate Arduino. In addition to feeding it at 3V3, the reset pin and the activation pin of the integrated must be connected to a high level (enable). Of course, the RX pin of one must connect to the TX of the other.

    To simplify the previous diagram, a plate has been represented Arduino powered at 3V3 and for which a voltage on the serial port is also assumed to be 3V3. If you use a microcontroller with a different signal level on the serial port (typically 5 V) will be necessary, so as not to damage the ESP8266, use a level converter like those in the diagrams below. This circuit is frequently found in many commercial off-the-shelf module implementations.

    5V to 3V3 Signal Level Converter for ESP8266 WiFi Module and Arduino

    Update ESP8266 firmware

    All the ESP8266 AT commands, its termination, the default speed of the module... depend on the version of the ESP8266 firmware. It is best to ensure that you have the same version in all modules and, if possible, that it is the latest version.

    Unfortunately, most of the ESP8266 wifi module models They only have 4Mbit, so the latest version cannot be installed on them. The latest (official) version of firmware that can be installed on ESP8266 wifi modules with 4 Mbit (most) is 0.9.4 which includes version 0.2 of the ESP8266 AT commands.

    In summary, to update the firmware you need:

    1. Download the corresponding firmware version. The latest (official) version for a module with 4Mbit of memory, found in the Espressif folder on github. In the Espressif website You can download the most recent version of the firmware, but it is very important to verify that the module on which it is installed has enough memory.

    2. Download the latest version of the firmware installation tool. My favorite is esptool which is written in Python, so it works on any platform. In addition to being downloaded, it can also be installed with pip install esptool (o pip2 o python -m pip…). Of course, Espressif It also offers its own tool but is currently only available for Windows.

    3. Prepare downloaded files; unzip them in an accessible folder and, if necessary, make the tool executable esptool, in my case, since GNU / Linux, with chmod +x esptool

    4. Connect the module to the computer using a converter USB UART TTL that works at 3V3 or use a level converter if it works at 5 V. In addition to the power, you will have to connect TX to RX of the converter USB UART TTL, RX to TX, GPIO0 at low level (GND) and maybe GPIO2 at high level (in my tests it has worked both connecting it at low level and disconnecting it). If the module has the GPIO15 connection free (as occurs in the ESP-12) it must be connected to a low level. RESET, which would normally be at a high level during operation, can be left unconnected or connected to a high level by means of a resistor (10K, for example), since before starting recording it may be necessary to reset the device by connecting it to a low level .
      By powering up the module it will be available to update but, If a connection error is displayed, it will be necessary to reset it connecting RESET at a low level for an instant and then leaving it on air (without connecting) for the update process.
      The module has half ampere consumption peaks (up to 600 mA, according to some users) so it is important to use a power supply capable of supporting this consumption, especially for updating firmware.

      Connection wifi module ESP8266 ESP-01 to USB UART TTL converter update firmware

    5. Run the tool to update the firmware. In my case, I have saved the tool and firmware documents in step 3 in the same folder, so I run from the console:
      cd ~/Datos/firmwareESP8266 (change to the folder containing the tool and firmware)
      ./esptool.py --baud 115200 --port /dev/ttyUSB0 write_flash \
      0x00000 ./boot_v1.1.bin \
      0x01000 ./user1.bin \
      0x7C000 ./esp_init_data_default.bin \
      0x7E000 ./blank.bin

      --baud sets the speed of the ESP8266 (115200 baud in my case) and --port the serial port it connects to (in my case, emulated, the first USB). The different documents that make up the firmware go behind write_flash preceded by the address, with the user1.bin document containing the update payload.

      wifi ESP8266 firmware update esptool console capture

    Send commands to ESP8266 wifi module

    To control the ESP8266 from a computer we will have to start with configure the app for which it will be enough to ① choose the port to which the converter is connected USB UART TTL, something like /dev/USB0 in GNU/Linux and similar or something like COM6 in Windows, ② choose the speed at which the ESP8266, probably 115200 baud, ③ set 8 data bits plus one stop bit, without parity or handshake, and ④ set end of line, depending on the firmware, almost always CR+LF.

    Configure CuteCom to monitor ESP8266 wifi module using a USB UART TTL converter

    Configure PuTTY to monitor the ESP8266 wifi module with a USB UART TTL converter

    Once the application is configured (or, where appropriate, stored and selected), it is open the connection ("open device" and "open", respectively, in the screenshots of the examples above with CuteCom y PuTTY) and you can start sending orders to ESP8266.

    As can be seen in the ESP8266 AT command table, the format for activating, deactivating, setting a value and referring to it is quite predictable, but in general it is not easy to remember them all and you will probably need to have it on hand to refer to it.

    The way of send AT orders al ESP8266 wifi module from Arduino is very simple: ① configure communications with Serial.begin(115200); (or Serial1, Serial2… on boards with several hardware serial ports) and ② send the commands using the format Serial.print(orden+"\r\n");

    The example above shows how to send the ESP8266 wifi module AT orders from Arduino. In this case it is illustrated AT+CWJAP, which is used to connect to an access point. This command uses as arguments the access point identifier (SSID) and the key, both in quotes, so they become an object Srtring and enclose them in quotes using the escape code (\"). To complete the order, use \r\n which corresponds to CR y LF.

    To remember that the serial port is not always identified with Serial (on certain plates it can be Serial1, Serial2…) the port object used has been defined by assigning it to the macro PUERTO_SERIE. Detecting the type of board used could add a bit of intelligence to serial port selection; Later we will go over how you can find out the type of Arduino. The rest of the definitions are the usual ones that allow you to "name" the constant values ​​to avoid repeating them (and making mistakes) and make it easier to change them.

    The above example is supposed to connect the ESP8266 wifi module to the indicated access point but was it already connected before? Has the connection worked? To know this, we need to "listen" to what the ESP8266

    Receive data from ESP8266 wifi module

    By connecting the data sniffer explained above to the computer you can see what Arduino has sent the ESP8266 and his response. To read from Arduino and process the information in it it will be necessary to detect with Serial.available() if any data has arrived and if so load it with Serial.read(). The following example shows how to read the response from AT+CWJAP?, which will report if there is a connection to any access point.

    Like on a plate Arduino Uno (and in others) opening the serial monitor resets the program, it can be used to see in the serial console Arduino the information you send to ESP8266 as the screenshot of the image below shows.

    Receive data from the ESP8266 wifi module from Arduino. Basic example

    Analyze the response sent by the ESP8266 wifi module

    We have already seen how to read the information that reaches Arduino from the ESP8266. The problem you have to deal with is that you don't know when it will start to arrive, how long it will take to arrive, what length it will be... and it is not very efficient to wait for the response from the ESP8266 is received without letting the microcontroller perform other tasks in the meantime.

    A simple way to manage this circumstance is iterate on the data received looking for concrete answers with which, for example, activate indicators (flags or Boolean variables) that will determine whether to continue searching in the received text and what actions should be carried out based on the information that arrives from the ESP8266. While the response arrives microcontroller can dedicate to other tasks, for example, receiving data from sensors and processing it.

    Search for a text in the information received from the ESP8266

    To search the text that comes from the ESP8266 can be compare each letter received with the one that corresponds to the message you are looking for. It will be necessary to use a counter (or a pointer) that points to the letter to be compared; If the character that arrives from the ESP8266 is the same as the one being examined in the message, the counter advances, if it is different it is initialized.

    To know that the end has been reached, the next character of the searched message is consulted, which will be zero (\0) or the length of the message is stored to, by comparing it with the counter, know if the comparison has finished and therefore the ESP8266 wifi module has sent the wanted message.

    The following example uses the command AT+CWLAP which will return a list of access points and within them one called "wifi polaridad.es" is searched. Although we have chosen to verify that the last character is zero, as the buffer It only stores the searched text and its length is known, it could also be checked if such a number of correct letters have been received. With a LED connected to pin 2 it is reported that the expected text has been found.

    In the code of the previous example you can also see a way to choose the serial port depending on the type of board Arduino used. This example assumes that you have three types of boards for the project: one Arduino Unoa Arduino Mega 2560 and a Arduino Leonardo. If you work with a Arduino Uno it will be used Serial and otherwise Serial1.

    If you work with a plate Arduino Leonardo You can use the same method to stop the program and wait for the console (the serial port associated with Serial) is available.

    Search various texts in the ESP8266 response

    The code in the previous example is used to search for text in the information sent by the ESP8266 but the response may include different information depending on the operation. Suppose, to start with a simple case in the next example, that the text sent by the MCU ESP8266 es OK when the operation is performed correctly and ERROR Otherwise, as with the order AT+CWJAP?, which serves to verify if the ESP8266 wifi module is already connected to an access point.

    This new implementation of the same method, which searches for a match with several possible messages, allows you to choose between different actions depending on the response received from the ESP8266, simply turn on the LED corresponding.

    Limit the time it takes to receive a response

    Until now no reference has been made to a relevant issue: the maximum waiting time (timeout) before considering an operation failed. If for any reason the connection with the ESP8266 wifi module, the module with the access point, the access point with Internet or, for example, a hypothetical server is not available, the program may be blocked at one point waiting indefinitely, so a response will have to be articulated to such circumstances. The maximum wait time can be configured for the entire application, usually it will be more "generous" in that case, or individual wait times can be programmed for each operation.

    To check that (at least) a certain time interval has passed The "time" of the moment in which the account is started is usually subtracted from the current "time" and it is verified that the difference is greater than the desired limit. This "time" does not have to be real time, it usually corresponds to the interval that has passed since the MCU start counting time; This does not affect the program since what is interesting is elapsed time and not the absolute time.

    Usually, to check if a certain interval has elapsed, an expression of the type is used:

    The variable milisegundos_al_empezar contains the value of millis() of a certain moment in the execution from which it is timed, so it is not unusual that its name refers to the word "chronometer." The variable intervalo_de_tiempo contains the maximum number of milliseconds that makes the previous expression true, that is, it represents the timeout; It is usually a constant (or a macro) and, as in the previous case, the word "TIMEOUT" often appears in its name. If you work with very short intervals you can use micros() instead of millis() (microseconds instead of milliseconds) although it is much less common and much less precise.

    A long integer in Arduino (unsigned long) occupies 4 bytes (32 bits), so the largest value it can represent is 4294967295 (2 to the power of 32 minus one, because it starts at zero). on a plate Arduino While running continuously the millisecond counter will reset (return to zero) approximately every 50 days. When subtracting with unsigned data types the same behavior is reproduced (flipping the counter) so it is feasible to control the timeout indefinitely.

    The above code shows a very basic implementation of timeout limitation incorporating the lines marked with respect to the example that precedes it. Since the timeout verification is performed after processing the data arriving from the ESP8266 wifi module, the operation can be considered successful even if reception takes longer than the imposed waiting time.

    Execute a complex operation defined by multiple AT commands

    To have an example reference of the purpose of the application that exploits the ESP8266 wifi module, suppose it is store information in a database accessed through a web service to keep track of the temperature. The following code reads a sensor connected to an analog input every certain time interval, calculates the average value and, after a longer time interval, sends it to the web server (style IoT) through a request HTTP (POST, GET…).

    In this temperature recording example, a web server is accessed every five minutes. Although the availability is not particularly high, it is to be expected that the proposal would work, but if a higher recording frequency were necessary, other resources would have to be implemented, for example, a data buffer waiting to be sent, to send several when the server can attend and store them for when it is not available. If the frequency with which data needs to be recorded was even greater, other types of protocols would have to be proposed as an alternative to the HTTP or even replace TCP by UDP to be able to send most of the data at the required speed even at the cost of losing some.

    The operations that make up the task to be carried out to send the temperature would be:

    • Reset the wifi module
    • Disconnect from the current access point (in case a default connection exists)
    • Set the settings. For the example, it is assumed that the connection mode (simple) and the role in Wi-Fi communications (station) must be configured.
    • Connect to access point
    • Verify that the connection is correct (actually, this is the entry point) If there is no connection, start the process from the beginning
    • Connect to server
    • Send the request HTTP with the data to be stored

    The order of operations does not have to be exactly like this (although the operation is) and each step may require several ESP8266 AT commandsFor example, the configuration listed above would need two: AT+CIPMUX=0 y AT+CWMODE=1.

    A data structure to represent operations on the ESP8266

    In the previous examples, although in a very basic way, a generic solution to the problem is already suggested: use a data structure that stores the possible responses and the actions that must be taken in each case; send an action, wait for a response, and proceed according to what the response means. Since each complex operation will require several ESP8266 AT commands, the data structure must link an operation with others, subsequent or previous, which must be carried out in each case depending on the response of the ESP8266.

    In the previous examples, a message was searched within the response of the ESP8266 and it was interpreted as success or error. In addition to a reception (and analysis) of all the text received, To have a generic minimum, it is advisable to also attend to the completion of the message or, in other words, to the availability of the ESP8266 wifi module to receive new orders. In this way, the change to a state that we could call, for example, "wifi available", could be receiving the name of the access point and receiving the text ERROR or the text OK would mean that the ESP8266 you have finished the response and you can now send the next one AT command to ESP8266.

    The code above uses a vector (operacion) to store the text of the successive operations that form the complete task. A two-dimensional array is used (mensaje) with the three responses that are analyzed. As explained above, it is necessary to look for the messages that represent the end of the response in addition to the message that represents a correct or incorrect response. Not all operations will have the same number of possible answers; When there are fewer responses, an empty message can be used that consumes the smallest possible number of cycles in its analysis (even so, it is not the most optimal way). Logically, it will be necessary for the minimum number of responses sought (three in the example) to include all the operating possibilities, even if they are not all possible.

    When talking about the possible answers, it can already be seen that this example is not very useful for receiving data with an arbitrary format from a ESP8266 wifi module, but the thing is that, in the context of use with microcontrollers it is not usual; The most common thing is to send data collected by the sensors they have connected and/or receive information about what to do with the actuators it controls. Very valuable information, which can be predicted very well.

    In the previous data structure, just as it is done to express the possible responses that are analyzed, a two-dimensional matrix is ​​also used to determine the operation that must be performed in each case (siguiente_operacion). Specifically, we have chosen to respond to three types of messages: ① an arbitrary text (LITERAL) to verify if there is a connection to the Wi-Fi access point and the server, ② a text to detect errors in the process (FALLO) and ③ a text indicating that the operation was completed successfully (ACIERTO).

    Finally, there are two more vectors to set the maximum wait time before giving up (timeout) and specify (configuracion) if the operation ends without waiting for a response (ESPERAR_RESPUESTA) and messages indicating the end of the communication. This last vector, to illustrate an example of how memory could be saved, works with the bits of a configuration byte to indicate the different states.

    The first ESP8266 AT commands of the data structure always expect a response, which can be the success or error message. When an error occurs, the module is restarted and it starts again and if the message indicates that the operation is correct, it moves on to the next one.

    When you have connected to the server, the pattern changes. In this case it is necessary to ① send the length of the data packet to be transmitted and ② compose the request HTTP with a fixed text plus the value (of the temperature) that is sent to be stored on the server. The preparation of this data is carried out in each shipment and it is necessary to divide it into two (notify the length) or three (send the request HTTP) the ESP8266 AT order. Only the last of the parts into which the operation is divided will wait for a response.

    In this case it will work without problems (maybe warning that the module is busy) but when the length of the data is greater it will be necessary to divide the data blocks into smaller pieces and it may even be necessary to implement a wait, as is done with the temperature reading, to give the module time to send the data without filling its buffer.

    Together with other macros that have already been explained before, the example code above shows how the different states are defined with which to specify whether to wait for a response and, if applicable, what message indicates that it has finished.

    As at different points in the code an operation will be sent (when it is time to send the average temperature, if the waiting time of an operation is exceeded, when the current operation is successfully completed...) but how to do it is established globally, it has been defined a macro ENVIAR_OPERACION which groups the steps involved in shipping.

    The following is the code of the main program of the example. The most external task is the one in charge of sampling the temperature to calculate the average and, every certain period of time, it is sent to the server using the ESP8266 wifi module. Once each operation is sent, the response is analyzed to determine which is next or if the task of sending information has been completed.

    Logically, several optimization actions can be carried out on the previous code but, as this is an example to understand how the ESP8266 In a generic way, it is only worth focusing on some aspects, the first being the data structure. It seems that the logical thing is use a programming language data structure (struct) to represent the information being processed: The ESP8266 AT commands and the messages that are analyzed.

    Use a structure (struct) to store the data instead of the example arrays (based on them) is trivial and, although it may result in more elegant code, it does not imply any improvement in the result. The true alternative posed by the use of struct is to implement, as explained below, variable lengths in structures that contain “inner” data that are referred to by them. In this way, for example, it would not be necessary for an operation to have a fixed number of responses to analyze.

    This approach suggests that it is the best way to implement the solution but the drawback is that it would be necessary use dynamic memory allocation, a risky practice working with a microcontroller which requires careful measurement of how much memory will be used at runtime, since the compiler will hardly be able to warn us about this and there is a certain possibility of exhausting the memory (or the stack) with fatal consequences for the execution of the program.

    In the line of optimizing the code, it is interesting to remember that, in a program of this type, which uses a large amount of text, can save memory space SRAM storing text strings in program memory (flash) with the macro F(). In the following screenshots you can see the different program and dynamic memory distribution with normal use of text and using the macro F().

    Arduino code example using text stored in program memory (flash)
    Arduino code example using text in SRAM

    With respect to the actions that are executed according to the information that arrives from the ESP8266 wifi module, as an alternative to checking the message from the code and performing one or the other according to what is received, can be stored in this data structure pointers to functions that perform each task instead of status indicators (flags) that warn of a certain state that the application is responsible for managing, for example, within the main loop.

    The following is an example of structures to store the data of the requests to the ESP8266 (the data type operacion_esp8266) and their responses (the data type respuesta_esp8266).

    As the structure that represents the operation (the data that is sent to the ESP8266 wifi module) refers to the structure with which the responses are defined, and the structure of the responses to the structure of the operations, it is necessary to declare both first, by defining the new data type, and then defining its contents.

    The previous example considers that the program that includes it has chosen to use a status indicator, which must correspond to a variable accessible from the code that is responsible for performing one or other operations as indicated by said value. If in the response of ESP8266 When a certain text is analyzed, the state takes the value that indicates the structure of the corresponding response.

    As said before, another alternative, either to replace or complement a status indicator, would be store a function in the reference structure (a pointer) that would be called upon encountering certain text in the response from the ESP8266 wifi module.

    In the previous example, it has been added to the data structure that is used to process the response from the ESP8266 wifi module a pointer to a (supposed) function that returns a data of type float (could be the weighted value of an analog reading) and to which two bytes are provided as arguments (two unsigned char which could be the pin from which the analog input is read and the one that activates the ENABLE of a hypothetical integrated).

    In development for MCU, contrary to what occurs in the development style for larger systems, it is not so uncommon to use global variables when defining the (global) behavior of the application that controls an assembly, so it will not be especially rare to find this type of definitions as functions without parameters and that do not return values, something like void (*accion)();

    If you work with this way of representing the data, using struct of variable length data, it will be necessary to dynamically allocate memory with malloc() (o new(), if objects are used), which will use the amount of memory allocated as a parameter and return a pointer to the beginning of the memory area that is reserved. With sizeof() On the type that are stored, multiplied by the number of elements used, you can get the amount of memory that is needed. An example with and without using it can be seen in the screenshots below. malloc(); Be careful with the memory used by the program in the first case, you need to load the library that contains this function.

    Example of memory allocation with malloc on Arduino

    Example of text assignment without malloc in Arduino

    If the operations on the ESP8266 wifi module will vary throughout the execution of the program, it will be necessary to free the memory that is not used with free() (o delete(), in the case of being objects). Although it is reasonable to expect that the compiler (GCC) will optimize the program to avoid memory partitioning, surely the performance will not be as optimal as working with statically allocated memory.

    Although in this example (in both implementations) it does not make much sense, in order to generalize the operation to be able to apply it to other cases, it should be noted that sending data always repeats the same protocol: notify the number of bytes that will be sent, wait for the indicator (>) and send the data.

    Since in this example it is only used once (the entire request is made in one packet), it does not seem very useful but, in general, it may be necessary to perform several sends in the same operation, including cases in which they must be transmitted significant amounts of data that must be fragmented to avoid overflowing the memory of the ESP8266.

    To implement this behavior, the last two elements of the connection can be used so that each time the data is sent, the data is filled with the corresponding values: in the first case, the number of bytes sent and in the second, the (part of the) request. to be transmitted.

    To repeat the assignment and sending of the different elements that must be transmitted can be stored in a vector. This new vector will be the one that determines the end of the complex operation and not the last operation as until now.

    1 comment

    comments user
    watch live football

    There is definitely a lot to find out about this subject. I like all the points you made

    Post Comment

    You May Have Missed