TCP Client using SIM900A GPRS and PIC18F4550

Introduction

SIM900 enables GPRS to embedded applications. We can implement TCP Client protocol using SIM900 TCP function AT Commands.

The Transmission Control Protocol (TCP) is a standard transport layer internet protocol which used in establishing and maintaining communication between server and client.

It is widely used in IoT (Internet of Things) embedded applications, where every sensor is connected to a server and we have access to control them over the internet.

To know about SIM900 GSM/GPRS Module refer to SIM900

 

Interfacing Diagram of SIM900 GSM module to PIC18F4550

This is the picture of TCP Client Implementation by interfacing PIC18F4550 with SIM900 GPRS
PIC18F4550 Interfacing with SIM900 GSM module

 

TCP Client over GPRS

Let’s program PIC18F4550 to configure SIM900A as TCP Client and Send/Receive data to/from the server using GPRS.

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

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 a below 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 the channel available to use as public.

For TCP RECEIVE use below AT command steps shown in the screenshot of RealTermSerial Terminal.

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

TCP Received Responses
TCP Received  Responses

 

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

TCP 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			"C7JFHZY54GLCJY38"
#define CHANNEL_ID			"119922"
#define APN					"internet"
#define USERNAME			""
#define PASSWORD			""

 

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

Program for TCP Client

/* 
 * TCP Client using GPRS & 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		200
#define DEFAULT_TIMEOUT			20000
#define DEFAULT_CRLF_COUNT		2

/* 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 APN					"internet"
#define USERNAME			""
#define PASSWORD			""

enum SIM900_RESPONSE_STATUS {
	SIM900_RESPONSE_WAITING,
	SIM900_RESPONSE_FINISHED,
	SIM900_RESPONSE_TIMEOUT,
	SIM900_RESPONSE_BUFFER_FULL,
	SIM900_RESPONSE_STARTING,
	SIM900_RESPONSE_ERROR
};

int8_t Response_Status, CRLF_COUNT = 0;
uint16_t Counter = 0;
uint32_t TimeOut = 0;
char RESPONSE_BUFFER[DEFAULT_BUFFER_SIZE];
char CONNECTION_NUMBER[] = "1";

void MSdelay(unsigned intval)
{
     unsigned inti,j;
	for(i = 0; i<= val; i++)
	for(j = 0; j < 165; j++);               /* 1 ms delay for 8MHz Frequency */
}

void Read_Response()
{
  char CRLF_BUF[2];
  char CRLF_FOUND;
  uint32_t TimeCount = 0, ResponseBufferLength;
  while(1)
  {
      if(TimeCount>= (DEFAULT_TIMEOUT+TimeOut))
    {
	CRLF_COUNT = 0; TimeOut = 0;
	Response_Status = SIM900_RESPONSE_TIMEOUT;
	return;
    }
    if(Response_Status == SIM900_RESPONSE_STARTING)
    {
	CRLF_FOUND = 0;
	memset(CRLF_BUF, 0, 2);
	Response_Status = SIM900_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(CRLF_BUF, CRLF_BUF + 1, 1);
		   CRLF_BUF[1] = RESPONSE_BUFFER[i];
		   if(!strncmp(CRLF_BUF, "\r\n", 2))
		    {
			if(++CRLF_FOUND == (DEFAULT_CRLF_COUNT+CRLF_COUNT))
			{
		          CRLF_COUNT = 0; TimeOut = 0;
			  Response_Status = SIM900_RESPONSE_FINISHED;
			  return;
			}
		    }
		}
	    CRLF_FOUND = 0;
	  }
      }
      MSdelay(1);
      TimeCount++;
   }
}

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

void Start_Read_Response()
{
	Response_Status = SIM900_RESPONSE_STARTING;
	do {
		Read_Response();
	} while(Response_Status == SIM900_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)
{
	Buffer_Flush();
	MSdelay(200);
	Start_Read_Response();		/* First read response */
	if((Response_Status != SIM900_RESPONSE_TIMEOUT) && 
	(strstr(RESPONSE_BUFFER, ExpectedResponse) != NULL))
	return true;			/* Return true for success */
	return false;			/* Else return false */
}

bool SendATandExpectResponse(const char* ATCommand, const char* ExpectedResponse)
{
	USART_SendString(ATCommand);	/* Send AT command to SIM900 */
	USART_TxChar('\r');
	return WaitForExpectedResponse(ExpectedResponse);
}

bool TCPClient_ApplicationMode(uint8_t Mode)
{
	char _buffer[20];
	sprintf(_buffer, "AT+CIPMODE=%d\r", Mode);
	_buffer[19] = 0;
	USART_SendString(_buffer);
	return WaitForExpectedResponse("OK");
}

bool TCPClient_ConnectionMode(uint8_t Mode)
{
	char _buffer[20];
	sprintf(_buffer, "AT+CIPMUX=%d\r", Mode);
	_buffer[19] = 0;
	USART_SendString(_buffer);
	return WaitForExpectedResponse("OK");
}

bool AttachGPRS()
{
	USART_SendString("AT+CGATT=1\r");
	return WaitForExpectedResponse("OK");
}

bool SIM900_Start()
{
	for (uint8_t i=0;i<5;i++)
	{
		if(SendATandExpectResponse("ATE0","OK")||SendATandExpectResponse("AT","OK"))
		return true;
	}
	return false;
}

bool TCPClient_Shut()
{
	USART_SendString("AT+CIPSHUT\r");
	return WaitForExpectedResponse("OK");
}

bool TCPClient_Close()
{
	USART_SendString("AT+CIPCLOSE=1\r");
	return WaitForExpectedResponse("OK");
}

bool TCPClient_Connect(const char* _APN, const char* _USERNAME, const char* _PASSWORD)
{

	USART_SendString("AT+CREG?\r");
	if(!WaitForExpectedResponse("+CREG: 0,1"))
	return false;

	USART_SendString("AT+CGATT?\r");
	if(!WaitForExpectedResponse("+CGATT: 1"))
	return false;

	USART_SendString("AT+CSTT=\"");
	USART_SendString(_APN);
	USART_SendString("\",\"");
	USART_SendString(_USERNAME);
	USART_SendString("\",\"");
	USART_SendString(_PASSWORD);
	USART_SendString("\"\r");
	if(!WaitForExpectedResponse("OK"))
	return false;

	USART_SendString("AT+CIICR\r");
	if(!WaitForExpectedResponse("OK"))
	return false;

	USART_SendString("AT+CIFSR\r");
	if(!WaitForExpectedResponse("."))
	return false;

	USART_SendString("AT+CIPSPRT=1\r");
	return WaitForExpectedResponse("OK");
}

bool TCPClient_connected() {
	USART_SendString("AT+CIPSTATUS\r");
	CRLF_COUNT = 2;
	return WaitForExpectedResponse("CONNECT OK");
}

uint8_t TCPClient_Start(const char* Domain, const char* Port)
{
	USART_SendString("AT+CIPMUX?\r");
	if(WaitForExpectedResponse("+CIPMUX: 0"))
	USART_SendString("AT+CIPSTART=\"TCP\",\"");
	else
	{
		USART_SendString("AT+CIPSTART=\"");
		USART_SendString(CONNECTION_NUMBER);
		USART_SendString("\",\"TCP\",\"");
	}
	
	USART_SendString(Domain);
	USART_SendString("\",\"");
	USART_SendString(Port);
	USART_SendString("\"\r");

	CRLF_COUNT = 2;
	if(!WaitForExpectedResponse("CONNECT OK"))
	{
		if(Response_Status == SIM900_RESPONSE_TIMEOUT)
		return SIM900_RESPONSE_TIMEOUT;
		return SIM900_RESPONSE_ERROR;
	}
	return SIM900_RESPONSE_FINISHED;
}

uint8_t TCPClient_Send(char* Data)
{
	USART_SendString("AT+CIPSEND\r");
	CRLF_COUNT = -1;
	WaitForExpectedResponse(">");
	USART_SendString(Data);
	USART_SendString("\r\n");
	USART_TxChar(0x1A);

	if(!WaitForExpectedResponse("SEND OK"))
	{
		if(Response_Status == SIM900_RESPONSE_TIMEOUT)
		return SIM900_RESPONSE_TIMEOUT;
		return SIM900_RESPONSE_ERROR;
	}
	return SIM900_RESPONSE_FINISHED;
}

void interrupt ISR()			 /* Receive ISR routine */
{
    uint8_t oldstatus = STATUS;
    INTCONbits.GIE = 0;
    char received_char;
    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;
        }
    }
    INTCONbits.GIE = 1;
    STATUS = oldstatus;
}

intmain()
{
	char _buffer[100];

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

	while(!SIM900_Start());
	TCPClient_Shut();
	TCPClient_ConnectionMode(0);	/* 0 = Single; 1 = Multi */
	TCPClient_ApplicationMode(0);	/* 0 = Normal Mode; 1 = Transperant Mode */
	AttachGPRS();
	while(!(TCPClient_Connect(APN, USERNAME, PASSWORD)));

	while(1)
	{
		TCPClient_Start(DOMAIN, PORT);

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

 

SIM900 Response

At the client end, we need to check SIM900 responses. We can check it on the serial terminal of the PC/Laptop. Connect SIM900 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 the below figure. connect USB to serial converter to PC/Laptop. Open the serial terminal on the PC/Laptop to see the SIM900 responses for the AT command sent from PIC microcontroller.

This is the picture of PIC18F4550 Interface with SIM900 GSM alongwith PC
PIC18F4550 Interface with SIM900 GSM along with PC 

 

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

TCP SEND response

 

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

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

TCP Received Responses

 

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”:”2”. 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 the Thingspeak server and sending the incremented count at field1 on a server. We get incremented count at field1 of Thingspeak server as shown in the below figure.

Data on Thingspeak Server
Data on Thingspeak Server

Components Used

SIM900A GSM GPRS Module
SIM900A is dual band GSM/GPRS 900/1800MHz module board used to utilize GSM and GPRS services around the globe. It is used to make/receive voice calls, send/receive text messages, connect to and access the internet over GPRS.
1
PIC18f4550
PIC18f4550
1
PICKit 4 MPLAB
PICKit 4 MPLAB
1
USB to Serial Converter CP2104
USB to Serial Converter CP2104
1

Downloads

Sim900A AT Commands Download
Sim900A TCPIP AT Commands Download
PIC18F4550 GPRS TCPClient Project File Download
Ad