Micro:bit - Getting On WiFi
Written by Harry Fairhead   
Monday, 11 July 2022
Article Index
Micro:bit - Getting On WiFi
AT Commands
Utilities
Configuring WiFi
A Web Server
Full Listing
Summary

AT Commands

The key idea in using the ESP8266 is that the micro:bit has to send an AT command, literally the characters AT, followed by other command strings. The command has to end with \r\n for the ESP8266 to take notice of it.

You can find a full list of commands at the Espressif website, but the most important are:

AT  		Attention
AT+RST     	Reset the board
AT+GMR     	Firmware version
AT+CWMODE= Operating Mode 1-Client 2-Access Point 3-Client and
Access Point
AT+CWJAP= Join network
AT+CWLAP View available networks
AT+CWQAP Disconnect from network
AT+CIPSTATUS Show current status as socket client
or server
AT+CIPSTART= Connect to socket server
AT+CIPCLOSE Close socket connection
AT+CIFS Show assigned IP address when connected to network
AT+CIPMUX= Set connection 0-Single Connection
1-Multi-Channel Connection
AT+CIPSERVER= Open the Socket Server
AT+CIPMODE= Set transparent mode
AT+CIPSTO= Set auto socket client
disconnect timeout from 1-28800s +IPD Data

This is just a very general overview and omits the commands that allow the device to work as an access point. It is assumed that client mode is the more common application, but it isn't difficult to extend this example to access point operation.

Setup

We need a function to set up the hardware ready to communicate with the device:

V1

void initWiFi() {
   uBit.serial.redirect(Tx, Rx);
   uBit.serial.baud(115200);
   uBit.serial.setRxBufferSize((uint8_t)+500);
}

V2

void initWiFi() {
   uBit.serial.redirect(uBit.io.P1 , uBit.io.P2);
   uBit.serial.setBaudrate(115200);
   uBit.serial.setRxBufferSize((uint8_t)+500);
}
    

The pins that we are using are P0 and P1, but to allow for other choices Tx and Rx are defined as constants at the start of the program:

V1

#define Tx MICROBIT_PIN_P0
#define Rx MICROBIT_PIN_P1

V2

#define Tx  uBit.io.P0
#define Rx  uBit.io.P1

The model of ESP8266 used works at 115200 baud by default. Newer models and up-dated firmware are reported to work at 9600 baud. If this is the case, you need to modify the data rate and/or change the ESP8266's baud rate.

Attention!

To start with the easiest, but possibly least useful, command let's implement some functions that test that we have a connection to the device, always a good thing to start with.

In this section we develop the first of a number of functions that send a command to the device and get back a response. To do this we need a few other functions to help and these are reused in other AT functions. Once you have one AT function the rest are very similar, so it is worth spending some time following how this most simple AT function works.

If you send the string AT\r\n then the ESP8266 replies with a single "OK".
This proves that the serial interface is working and there isn't much point in moving on until you have tested it works.

The AT function is simply:

int ATWiFi() {
    uBit.serial.send("AT\r\n", SYNC_SPINWAIT);
    return 1;
}

You have to use SPINWAIT because things go wrong when you let the fiber continue to process while the data is being transmitted.

This is the most basic form of function that will do the job, but it isn't really practical. We need to check that it works and we need to get some feedback. We could read what is sent back and then display it on the LED display. This would work, but reading the LED display is very slow for a human. A better idea is to send the data to the USB serial console when in a "debug" mode. The problem with this is that every time you switch pins the serial device generates spurious characters. If we switch after receiving the entire message rather than on each character we can minimize the spurious characters, which the ESP8266 seems to ignore.

A function to swap to and from the USB pins and send the data is easy:

void debug(ManagedString s) {
    uBit.serial.redirect(USBTX, USBRX);
    uBit.serial.send(s, SYNC_SPINWAIT);
    uBit.serial.redirect(Tx, Rx);
}

For V2 you also need:

#define USBTX uBit.io.usbTx
#define USBRX uBit.io.usbRx

Now all we need to do is read the data sent back from the device. The simplest way of doing this is to wait for a period of time that means that the device has to have sent the data or there is something wrong. As 115200 baud allows for more than 100 characters in 10ms and 9600 baud takes just more than 100ms, you can estimate the time you need to wait for any packet of text to be delivered. As the response to the AT request only sends a few characters, waiting 150ms is more than enough at any baud rate. We can then read the entire buffer:

uBit.sleep(150);
ManagedString s = uBit.serial.read(500, ASYNC);

Reading in ASYNC mode means that the function will return as many characters are in the buffer as a managed string.

If the AT command has been successful, it returns a string containing "OK". One of the problems of working with AT commands is that they don't have an exact syntax and there is no formal "end of message" signal.

By observation, any successful command does end with OK and if you can't find OK in the response then you either haven't read it all or there has been an error. Clearly we need a way to test if a string contains OK;

int find(ManagedString c, ManagedString s) {
    int i;
    for (i = 0; i < (s.length() - c.length()); i++) {
        if (c == s.substring(i, c.length())) break;
    }
    if (i == (s.length() - c.length())) return 0;
    return 1;
}

This is the simplest string scanning function that will do the job. It only checks that the string c is in s once and it will find c if it is embedded in another word. So it will find “OK” in "NotOK", for example.

With all of this we can now finish the ATWiFi function:

int ATWiFi() {
    uBit.serial.send("AT\r\n", SYNC_SPINWAIT);
    uBit.sleep(150);
    ManagedString s = uBit.serial.read(500, ASYNC);
    if (DEBUG)debug("\n\rAT \n\r" + s + "\n\r");
    return find("OK", s);
}

If the constant DEBUG is a 1 then the string is printed to the USB port and you can examine it:

#define DEBUG 1


Last Updated ( Tuesday, 12 July 2022 )