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
TCP Client over GPRS
Let’s program AVR ATmega16 to configure SIM900A as TCP Client and Receive/Send data to/from the server using GPRS.
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.
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).
For the TCP SEND method use below AT command steps shown in the screenshot of RealTerm Serial Terminal.
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
/*
* ATmega16_GPRS_TCPClient
* http://www.electronicwings.com
*
*/
#define F_CPU 8000000UL /* Define CPU clock Frequency e.g. here its 8MHz */
#include <avr/io.h> /* Include AVR std. library file */
#include <string.h> /* Include string library */
#include <stdio.h> /* Include standard IO library */
#include <stdlib.h> /* Include standard library */
#include <stdbool.h> /* Include standard boolean library */
#include <util/delay.h> /* Include delay header file */
#include <avr/interrupt.h> /* Include avr interrupt header file */
#include "USART_RS232_H_file.h" /* Include USART header file */
#define SREG _SFR_IO8(0x3F)
#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 Read_Response() /* Read response */
{
static char CRLF_BUF[2];
static 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)
{
_delay_ms(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;
}
}
_delay_ms(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(char* ExpectedResponse)
{
Buffer_Flush();
_delay_ms(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(char* ATCommand, 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(char* _APN, char* _USERNAME, 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(char* Domain, 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;
}
ISR (USART_RXC_vect) /* Receive ISR routine */
{
uint8_t oldsrg = SREG;
RESPONSE_BUFFER[Counter] = UDR; /* Copy data to buffer & increment counter */
Counter++;
if(Counter == DEFAULT_BUFFER_SIZE)
Counter = 0;
SREG = oldsrg;
}
int main()
{
char _buffer[100];
#ifdef SEND_DEMO
uint8_t Sample = 0;
#endif
USART_Init(9600); /* Initiate USART with 9600 baud rate */
sei(); /* Start global 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);
_delay_ms(600);
TCPClient_Close();
_delay_ms(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);
_delay_ms(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 Atmega16 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 the Atmega16 microcontroller.
Now for TCP SEND commands (sent from ATmega16 Microcontroller), we can see the below response from SIM900 on the serial terminal for the Thingspeak server.
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 ATmega16 Microcontroller), we can see the below response from SIM900 on the serial terminal for the Thingspeak server.
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 the server. We get incremented count at field1 of Thingspeak server as shown in below figure.
Components Used |
||
---|---|---|
ATmega 16 ATmega 16 |
X 1 | |
Atmega32 Atmega32 |
X 1 | |
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. |
X 1 | |
CP2103 USB TO UART BRIDGE CP2103 is single chip USB to UART Bridge. It supports USB 2.0 protocol. |
X 1 |