PIC18F4550 Interface with WiFi ESP8266 module

Overview of ESP8266

The ESP8266 module is low-cost standalone wireless transceiver that can be used for end-point IoT developments.

ESP8266 module enables internet connectivity to embedded applications. It uses TCP/UDP communication protocol to connect with the server/client.

ESP8266 Module Diagram
ESP8266-01 Wi-Fi Module

 

To communicate with the ESP8266 module, the microcontroller needs to use a set of AT commands. The microcontroller communicates with the ESP8266-01 module using UART having a specified Baud rate (Default 115200).

To know more about the ESP8266 Module and its firmware refer to ESP8266 Module

Now let’s interface the ESP8266 Module with PIC18F4550

 

Connection Diagram of ESP8266 with PIC18F4550

PIC18F4550 Interface with ESP8266 Module
PIC18F4550 Interface with ESP8266 Module

 

TCP Client using ESP8266

Let’s program PIC18F4550 to configure the ESP8266 module as TCP Client and Receive/Send data from/to Server using WIFI.

Here, we are using the Thingspeak server for TCP Client demo purposes.

Thingspeak is an open IOT platform where anyone can visualize and analyze live data from their sensor devices. Also, we can perform data analysis on data posted by remote devices with Matlab code in Thingspeak. To learn more about Thingspeak refer link

https://thingspeak.com/pages/learn_more

Just sign up and create a channel. We have below the channel and write key on Thingspeak for data send and receive.

  • channel ID is = 119922
  • Write Key is = C7JFHZY54GLCJY38

Note:  Do not forget to tick the Make Public field in the channel setting option on your Thingspeak channel. It makes channels available to use as public. This allows any user to access channel data without any username & password.

For TCP RECEIVE method use below AT command steps shown in the screenshot of RealTerm Serial Terminal.

The below screenshot consists of AT commands (Green) and Responses (Yellow).

ESP8266 TCP receive Commands

 

For the TCP SEND method use below AT command steps shown in the screenshot of RealTerm Serial Terminal.

ESP8266TCP send commands

 

In the below program of TCP Client, do the following

For TCP Client RECEIVE demo

#define RECEIVE_DEMO			/* Define Receive demo */
//#define SEND_DEMO				/* Define Send demo */

For TCP Client SEND demo

//#define RECEIVE_DEMO			/* Define Receive demo */
#define SEND_DEMO				/* Define Send demo */

Edit Fields below with respective data

 

/* Define Required fields shown below */
#define DOMAIN				"api.thingspeak.com"
#define PORT				"80"
#define API_WRITE_KEY		"thingspeak Write Key"
#define CHANNEL_ID			"thingspeak Channel ID"

#define SSID				"WiFi SSID"
#define PASSWORD			"WiFi Password"

In the below program, we are using response-based functions to get status if things deviate from normal.

 

Code for TCP Client using ESP8266 & PIC

/* 
 * TCP Client using ESP8266 & PIC
 * http://www.electronicwings.com
 */

#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pic18f4550.h>
#include "USART_Header_File.h"
#include "Configuration_header_file.h"

#define DEFAULT_BUFFER_SIZE		160
#define DEFAULT_TIMEOUT			10000

/* Connection Mode */
#define SINGLE				0
#define MULTIPLE			1

/* Application Mode */
#define NORMAL				0
#define TRANSPERANT			1

/* Application Mode */
#define STATION				1
#define ACCESSPOINT			2
#define BOTH_STATION_AND_ACCESPOINT	3

/* Select Demo */
#define RECEIVE_DEMO			/* Define RECEIVE demo */
//#define SEND_DEMO			/* Define SEND demo */

/* Define Required fields shown below */
#define DOMAIN				"api.thingspeak.com"
#define PORT				"80"
#define API_WRITE_KEY			"C7JFHZY54GLCJY38"
#define CHANNEL_ID			"119922"

#define SSID				"ssid"
#define PASSWORD			"password"

enum ESP8266_RESPONSE_STATUS{
	ESP8266_RESPONSE_WAITING,
	ESP8266_RESPONSE_FINISHED,
	ESP8266_RESPONSE_TIMEOUT,
	ESP8266_RESPONSE_BUFFER_FULL,
	ESP8266_RESPONSE_STARTING,
	ESP8266_RESPONSE_ERROR
};

enum ESP8266_CONNECT_STATUS {
	ESP8266_CONNECTED_TO_AP,
	ESP8266_CREATED_TRANSMISSION,
	ESP8266_TRANSMISSION_DISCONNECTED,
	ESP8266_NOT_CONNECTED_TO_AP,
	ESP8266_CONNECT_UNKNOWN_ERROR
};

enum ESP8266_JOINAP_STATUS {
	ESP8266_WIFI_CONNECTED,
	ESP8266_CONNECTION_TIMEOUT,
	ESP8266_WRONG_PASSWORD,
	ESP8266_NOT_FOUND_TARGET_AP,
	ESP8266_CONNECTION_FAILED,
	ESP8266_JOIN_UNKNOWN_ERROR
};

int8_t Response_Status;
volatile int16_t Counter = 0, pointer = 0;
uint32_t TimeOut = 0;
char RESPONSE_BUFFER[DEFAULT_BUFFER_SIZE];

void Read_Response(char* _Expected_Response)
{
  uint8_t EXPECTED_RESPONSE_LENGTH = strlen(_Expected_Response);
  uint32_t TimeCount = 0, ResponseBufferLength;
  char RECEIVED_CRLF_BUF[30];

  while(1)
  {
    if(TimeCount >= (DEFAULT_TIMEOUT+TimeOut))
    {
	TimeOut = 0;
	Response_Status = ESP8266_RESPONSE_TIMEOUT;
	return;
    }

    if(Response_Status == ESP8266_RESPONSE_STARTING)
    {
	Response_Status = ESP8266_RESPONSE_WAITING;
    }

    ResponseBufferLength = strlen(RESPONSE_BUFFER);
    if (ResponseBufferLength)
    {
	MSdelay(1);
	TimeCount++;
	if (ResponseBufferLength==strlen(RESPONSE_BUFFER))
	{
	    for (uint16_t i=0;i<ResponseBufferLength;i++)
	    {
		memmove(RECEIVED_CRLF_BUF, RECEIVED_CRLF_BUF + 1, EXPECTED_RESPONSE_LENGTH-1);
		RECEIVED_CRLF_BUF[EXPECTED_RESPONSE_LENGTH-1] = RESPONSE_BUFFER[i];
		if(!strncmp(RECEIVED_CRLF_BUF, _Expected_Response, EXPECTED_RESPONSE_LENGTH))
		{
			TimeOut = 0;
			Response_Status = ESP8266_RESPONSE_FINISHED;
			return;
		}
	    }
	}
    }
    MSdelay(1);
    TimeCount++;
  }
}

void ESP8266_Clear()
{
	memset(RESPONSE_BUFFER,0,DEFAULT_BUFFER_SIZE);
	Counter = 0;	pointer = 0;
}

void Start_Read_Response(const char* _ExpectedResponse)
{
	Response_Status = ESP8266_RESPONSE_STARTING;
	do {
		Read_Response(_ExpectedResponse);
	} while(Response_Status == ESP8266_RESPONSE_WAITING);

}

void GetResponseBody(char* Response, uint16_t ResponseLength)
{

	uint16_t i = 12;
	char buffer[5];
	while(Response[i] != '\r')
	++i;

	strncpy(buffer, Response + 12, (i - 12));
	ResponseLength = atoi(buffer);

	i += 2;
	uint16_t tmp = strlen(Response) - i;
	memcpy(Response, Response + i, tmp);

	if(!strncmp(Response + tmp - 6, "\r\nOK\r\n", 6))
	memset(Response + tmp - 6, 0, i + 6);
}

bool WaitForExpectedResponse(const char* ExpectedResponse)
{
	Start_Read_Response(ExpectedResponse);	/* First read response */
	if((Response_Status != ESP8266_RESPONSE_TIMEOUT))
	return true;				/* Return true for success */
	return false;				/* Else return false */
}

bool SendATandExpectResponse(char* ATCommand, const char* ExpectedResponse)
{
	ESP8266_Clear();
	USART_SendString(ATCommand);		/* Send AT command to ESP8266 */
	USART_SendString("\r\n");
	return WaitForExpectedResponse(ExpectedResponse);
}

bool ESP8266_ApplicationMode(uint8_t Mode)
{
	char _atCommand[20];
	memset(_atCommand, 0, 20);
	sprintf(_atCommand, "AT+CIPMODE=%d", Mode);
	_atCommand[19] = 0;
	return SendATandExpectResponse(_atCommand, "\r\nOK\r\n");
}

bool ESP8266_ConnectionMode(uint8_t Mode)
{
	char _atCommand[20];
	memset(_atCommand, 0, 20);
	sprintf(_atCommand, "AT+CIPMUX=%d", Mode);
	_atCommand[19] = 0;
	return SendATandExpectResponse(_atCommand, "\r\nOK\r\n");
}

bool ESP8266_Begin()
{
	for (uint8_t i=0;i<5;i++)
	{
		if(SendATandExpectResponse("ATE0","\r\nOK\r\n")||SendATandExpectResponse("AT","\r\nOK\r\n"))
		return true;
	}
	return false;
}

bool ESP8266_Close()
{
	return SendATandExpectResponse("AT+CIPCLOSE=1", "\r\nOK\r\n");
}

bool ESP8266_WIFIMode(uint8_t _mode)
{
	char _atCommand[20];
	memset(_atCommand, 0, 20);
	sprintf(_atCommand, "AT+CWMODE=%d", _mode);
	_atCommand[19] = 0;
	return SendATandExpectResponse(_atCommand, "\r\nOK\r\n");
}

uint8_t ESP8266_JoinAccessPoint(const char* _SSID, const char* _PASSWORD)
{
	char _atCommand[60];
	memset(_atCommand, 0, 60);
	sprintf(_atCommand, "AT+CWJAP=\"%s\",\"%s\"", _SSID, _PASSWORD);
	_atCommand[59] = 0;
	if(SendATandExpectResponse(_atCommand, "\r\nWIFI CONNECTED\r\n"))
	return ESP8266_WIFI_CONNECTED;
	else{
		if(strstr(RESPONSE_BUFFER, "+CWJAP:1"))
		return ESP8266_CONNECTION_TIMEOUT;
		else if(strstr(RESPONSE_BUFFER, "+CWJAP:2"))
		return ESP8266_WRONG_PASSWORD;
		else if(strstr(RESPONSE_BUFFER, "+CWJAP:3"))
		return ESP8266_NOT_FOUND_TARGET_AP;
		else if(strstr(RESPONSE_BUFFER, "+CWJAP:4"))
		return ESP8266_CONNECTION_FAILED;
		else
		return ESP8266_JOIN_UNKNOWN_ERROR;
	}
}

uint8_t ESP8266_connected() 
{
	SendATandExpectResponse("AT+CIPSTATUS", "\r\nOK\r\n");
	if(strstr(RESPONSE_BUFFER, "STATUS:2"))
	return ESP8266_CONNECTED_TO_AP;
	else if(strstr(RESPONSE_BUFFER, "STATUS:3"))
	return ESP8266_CREATED_TRANSMISSION;
	else if(strstr(RESPONSE_BUFFER, "STATUS:4"))
	return ESP8266_TRANSMISSION_DISCONNECTED;
	else if(strstr(RESPONSE_BUFFER, "STATUS:5"))
	return ESP8266_NOT_CONNECTED_TO_AP;
	else
	return ESP8266_CONNECT_UNKNOWN_ERROR;
}

uint8_t ESP8266_Start(uint8_t _ConnectionNumber, const char* Domain, const char* Port)
{
	bool _startResponse;
	char _atCommand[60];
	memset(_atCommand, 0, 60);
	_atCommand[59] = 0;

	if(SendATandExpectResponse("AT+CIPMUX?", "CIPMUX:0"))
		sprintf(_atCommand, "AT+CIPSTART=\"TCP\",\"%s\",%s", Domain, Port);
	else
		sprintf(_atCommand, "AT+CIPSTART=\"%d\",\"TCP\",\"%s\",%s", _ConnectionNumber, Domain, Port);

	_startResponse = SendATandExpectResponse(_atCommand, "CONNECT\r\n");
	if(!_startResponse)
	{
		if(Response_Status == ESP8266_RESPONSE_TIMEOUT)
		return ESP8266_RESPONSE_TIMEOUT;
		return ESP8266_RESPONSE_ERROR;
	}
	return ESP8266_RESPONSE_FINISHED;
}

uint8_t ESP8266_Send(char* Data)
{
	char _atCommand[20];
	memset(_atCommand, 0, 20);
	sprintf(_atCommand, "AT+CIPSEND=%d", (strlen(Data)+2));
	_atCommand[19] = 0;
	SendATandExpectResponse(_atCommand, "\r\nOK\r\n>");
	if(!SendATandExpectResponse(Data, "\r\nSEND OK\r\n"))
	{
		if(Response_Status == ESP8266_RESPONSE_TIMEOUT)
		return ESP8266_RESPONSE_TIMEOUT;
		return ESP8266_RESPONSE_ERROR;
	}
	return ESP8266_RESPONSE_FINISHED;
}

int16_t ESP8266_DataAvailable()
{
	return (Counter - pointer);
}

uint8_t ESP8266_DataRead()
{
	if(pointer < Counter)
	return RESPONSE_BUFFER[pointer++];
	else{
		ESP8266_Clear();
		return 0;
	}
}

uint16_t Read_Data(char* _buffer)
{
	uint16_t len = 0;
	MSdelay(100);
	while(ESP8266_DataAvailable() > 0)
	_buffer[len++] = ESP8266_DataRead();
	return len;
}

void interrupt ISR()				/* Receive ISR routine */
{
    uint8_t oldstatus = STATUS;
    INTCONbits.GIE = 0;
    if(RCIF==1){
        RESPONSE_BUFFER[Counter] = RCREG;	/* Copy data to buffer & increment counter */
        Counter++;
        if(RCSTAbits.OERR)                      /* check if any overrun occur due to continuous reception */
        {           
            CREN = 0;
            NOP();
            CREN = 1;
        }
        if(Counter == DEFAULT_BUFFER_SIZE){
            Counter = 0; pointer = 0;
        }
    }
    INTCONbits.GIE = 1;
    STATUS = oldstatus;
}

int main(void)
{
	char _buffer[150];
	uint8_t Connect_Status;
	#ifdef SEND_DEMO
	uint8_t Sample = 0;
	#endif

	OSCCON = 0x72;				/* Set internal clock to 8MHz */
	USART_Init(115200);			/* Initiate USART with 115200 baud rate */
	INTCONbits.GIE=1;			/* enable Global Interrupt */
	INTCONbits.PEIE=1;			/* enable Peripheral Interrupt */
	PIE1bits.RCIE=1;			/* enable Receive Interrupt */	

	while(!ESP8266_Begin());
	ESP8266_WIFIMode(BOTH_STATION_AND_ACCESPOINT);/* 3 = Both (AP and STA) */
	ESP8266_ConnectionMode(SINGLE);		/* 0 = Single; 1 = Multi */
	ESP8266_ApplicationMode(NORMAL);	/* 0 = Normal Mode; 1 = Transperant Mode */
	if(ESP8266_connected() == ESP8266_NOT_CONNECTED_TO_AP)
	ESP8266_JoinAccessPoint(SSID, PASSWORD);
	ESP8266_Start(0, DOMAIN, PORT);
	while(1)
	{
		Connect_Status = ESP8266_connected();
		if(Connect_Status == ESP8266_NOT_CONNECTED_TO_AP)
		ESP8266_JoinAccessPoint(SSID, PASSWORD);
		if(Connect_Status == ESP8266_TRANSMISSION_DISCONNECTED)
		ESP8266_Start(0, DOMAIN, PORT);

		#ifdef SEND_DEMO
		memset(_buffer, 0, 150);
		sprintf(_buffer, "GET /update?api_key=%s&field1=%d", API_WRITE_KEY, Sample++);
		ESP8266_Send(_buffer);
		MSdelay(20000);	/* Thingspeak server delay */
		#endif
		
		#ifdef RECEIVE_DEMO
		memset(_buffer, 0, 150);
		sprintf(_buffer, "GET /channels/%s/feeds/last.txt", CHANNEL_ID);
		ESP8266_Send(_buffer);
		Read_Data(_buffer);
		MSdelay(600);
		#endif
	}
}

 

ESP8266 Response

At the client end, we need to check ESP8266 responses. We can check it on the serial terminal of PC/Laptop. Connect ESP8266 module transmit pin (TX) to the receive pin (RX) of PIC18F4550 Microcontroller and to the receive pin (RX) of usb to serial converter as shown in below figure. connect usb to serial converter to PC/Laptop. Open the serial terminal on PC/Laptop to see the ESP8266 responses for the AT command sent from PIC18F4550 microcontroller.

PIC18F4550 Interface with ESP8266 along with PC
PIC18F4550 Interface with ESP8266 along with PC

 

Now for TCP SEND commands (sent from PIC18F4550 Microcontroller), we can see the below response from ESP8266 on the serial terminal for the Thingspeak server.

thingspeak TCP send response

In response to TCP SEND we get the data entry no. as shown in the above figure i.e. 1131, 1132, and so on.

For TCP RECEIVE commands (sent from PIC18F4550 Microcontroller), we can see the below response from ESP8266 on the serial terminal for the Thingspeak server.

thingspeak TCP receive response

 

In response to TCP RECEIVE we get the last entry data for field1 on Thingspeak as shown in the above figure.

Note: here we are retrieving the last entry data on field1 of thingspeak server hence we get the last updated data of field1 from the server as shown in the above figure i.e. “field1”:”11”. In the program, we used "GET /channels/119922/feeds/last.txt" to receive the last updated data only.

Updates at Thingspeak server on TCP SEND

For TCP SEND we can see the output at the server end. Here we are using thingspeak server and sending the incremented count at field1 on the server. We get incremented count at field1 of thingspeak server as shown in the below figure.

 

field data on thingspeak server

Components Used

ESP8266 WiFi Module
ESP8266 is a system on chip (SoC) which provides WIFI capability for embedded applications. This enables internet connectivity to embedded applications. ESP8266 modules are mostly used in Internet of Things(IoT) applications.
1
PIC18f4550
PIC18f4550
1

Downloads

ESP8266 Datasheet Download
ESP8266 AT Commands Download
ESP8266 Getting Started Guide Download
PIC18F4550 ESP8266 WiFi Project file Download
Ad