Turn-key PCB assembly services in prototype quantities or low-volume to mid-volume production runs

Interfacing SIM300 GMS module to ATMEGA

Today’s tutorial is one of the most interesting tutorial in a practical sense. We will learn to interface a GSM modem with the AVR series which can be used to send and receive SMS and also to receive and send calls a well as to use GPRS. The module that will be using is the SIM300 module which as on board-support for RS-232 for computers as well as TTL ports for direct-interface to microcontrollers without any need for logic conversion.

sim300

A GSM/GPRS Module like SIM300 can be used for any embedded application that requires a long range communication, like a water pump in a rice field turned on in the morning by a farmer sitting in his house few kilometres away! You have few communication options depending on the application, such as a simple sms based communications or a call based communication.

The SIM300 KIT is a fully integrated module with SIM card holder, power supply etc. The basic communication is over asynchronous serial line. This is the most basic type of serial communication that’s why it is very popular and hardware support is available in most MCUs. The data is transmitted bit by bit in a frame consisting a complete byte. Thus at high level it is viewed as a simple text stream. There are only two streams one is from MCU to SIM300 and other is from SIM300 to MCU. Commands are sent as simple text.

For the purpose of the tutorial I will be using SIM300. However you can also use sim900. Both are easily available on online stores and they share a common commands. If you are planning to use it for GPRS based applications, I suggest you to buy SIM900 as it has a better functionality for GPRS based applications. Before beginning, I suggest you to acquire some basic information about UART of the AVR

Following are the functions in AVR USART library

char UReadData()

Reads a single character from the queue. Returns 0 if no data is available in the queue.

void USARTInit(uint16_t ubrrvalue)

Initializes the AVR USART Hardware. The parameter ubrrvalue is required to set desired baud rate for communication. By default SIM300 communicates at 9600 bps. For an AVR MCU running at 16MHz the ubrrvalue comes to be 103.

void UWriteString(char *str)

Writes a complete C style null terminated string to the Tx line.

uint8_t UDataAwailable()

Tells you the amount of data available in the FIFO queue.

void UWriteData(char data)

Writes a single byte of data to the Tx Line, used by UWriteString() function.

void UFlushBuffer()

Removes all waiting data in the fifo buffer. Generally before sending new command to GSM Module we first clear up the data waiting in the fifo.

All SIM300 commands are prefixed with AT+ and are terminated by a Carriage Return (or <CR> in short). The ASCII code of CR is 0x0D (decimal 13). Anything you write to SIM300 will be echoed back from sim300’s tx line. That means if you write a command which is 7 bytes long (including the trailing CR) then immediately you will have same 7 bytes in the MCU’s UART incoming buffer. If you don’t get the echo back then it means something is wrong!

So the first function we develop is SIM300Cmd (const char *cmd) which does the following job:-

1. Writes the command given by parameter cmd.

2. Appends CR after the command.

3. Waits for the echo, if echo arrives before timeout it returnsSIM300_OK (constant defined    in sim300.h). If we have waited too long and echo didn’t arrive then it returns SIM300_TIMEOUT.

int8_t SIM300Cmd(const char *cmd)
{
   UWriteString(cmd);   //Send Command
   UWriteData(0x0D); //CR
   uint8_t len=strlen(cmd);
   len++;   //Add 1 for trailing CR added to all commands
   uint16_t i=0;
   //Wait for echo
   while(i<10*len)
   {
      if(UDataAvailable()<len)
      {
         i++;
_delay_ms(10);
   continue;
      }
      else
      {
         //We got an echo
         //Now check it
         UReadBuffer(sim300_buffer,len);  //Read serial Data
return SIM300_OK;

      }
   }

   return SIM300_TIMEOUT;

}

Commands are usually followed by a response. The form of the response is like this

<CR><LF><response><CR><LF>

LF is Line Feed whose ASCII Code is 0x0A (10 in decimal)

So after sending a command we need to wait for a response, three things can happen while waiting for a response:

No response is received after waiting for a long time, reason can be that the SIM300 is not connected properly with the MCU.

Response is received but not as expected, reason can be faulty serial line or incorrect baud rate setting or MCU is running at some other frequency than expected.

Correct response is received.

For example, command Get Network Registration is executed like this:-

Command String: “AT+CREG?”

Response:

<CR><LF>+CREG: <n>,<stat><CR><LF>

<CR><LF>OK<CR><LF>

So you can see the correct response is 20 bytes. So after sending command “AT+CREG?” we wait until we have received 20 bytes of data or certain amount of time has elapsed. The second condition is implemented to avoid the risk of hanging up if the sim300 module malfunctions. That means we do not keep waiting forever for response we simply throw error if SIM300 is taking too long to respond (this condition is called timeout)

If correct response is received we analyses variable <stat> to get the current network registration.

Depending on current network registration status the value of stat can be

0 – not registered, SIM300 is not currently searching a new operator to register to

1 registered, home network

2 not registered, but SIM300 is currently searching a new operator to register to

3 registration denied

4 unknown

5 registered, roaming

int8_t SIM300GetNetStat()
{
   //Send Command
   SIM300Cmd("AT+CREG?");

   //Now wait for response
   uint16_t i=0;

   //correct response is 20 byte long
   //So wait until we have got 20 bytes
   //in buffer.
   while(i<10)
   {
      if(UDataAvailable()<20)
      {
         i++;

         _delay_ms(10);

         continue;
      }
      else
      {
         //We got a response that is 20 bytes long
         //Now check it
         UReadBuffer(sim300_buffer,20);   //Read serial Data

         if(sim300_buffer[11]=='1')
            return SIM300_NW_REGISTERED_HOME;
         else if(sim300_buffer[11]=='2')
            return SIM300_NW_SEARCHING;
         else if(sim300_buffer[11]=='5')
            return SIM300_NW_REGISTED_ROAMING;
         else
            return SIM300_NW_ERROR;
      }
   }

   //We waited so long but got no response
   //So tell caller that we timed out

   return SIM300_TIMEOUT;

}

Circuit used in experiment:

circuit_diagram

Main code:

#include <avr/io.h>
#include <util/delay.h>

#include "lib/lcd/lcd.h"
#include "lib/sim300/sim300.h"

void Halt();
int main(void)
{
	//Initialize LCD Module
	LCDInit(LS_NONE);

	//Intro Message
	LCDWriteString("SIM300 Demo !");
	LCDWriteStringXY(0,1,"By ABC");

	_delay_ms(1000);

	LCDClear();

	//Initialize SIM300 module
	LCDWriteString("Initializing ...");
	int8_t r= SIM300Init();

	_delay_ms(1000);

	//Check the status of initialization
	switch(r)
	{
		case SIM300_OK:
			LCDWriteStringXY(0,1,"OK !");
			break; 
		case SIM300_TIMEOUT:
			LCDWriteStringXY(0,1,"No response");
			Halt();
		case SIM300_INVALID_RESPONSE:
			LCDWriteStringXY(0,1,"Inv response");
			Halt();
		case SIM300_FAIL:
			LCDWriteStringXY(0,1,"Fail");
			Halt();
		default:
			LCDWriteStringXY(0,1,"Unknown Error");
			Halt();	
	}

	_delay_ms(1000);

	//IMEI No display
	LCDClear();

	char imei[16];

	r=SIM300GetIMEI(imei);

	if(r==SIM300_TIMEOUT)
	{
		LCDWriteString("Comm Error !");
		Halt();
	}

	LCDWriteString("Device IMEI:");
	LCDWriteStringXY(0,1,imei);

	_delay_ms(1000);

	//Manufacturer ID
	LCDClear();

	char man_id[48];

	r=SIM300GetManufacturer(man_id);

	if(r==SIM300_TIMEOUT)
	{
		LCDWriteString("Comm Error !");
		Halt();
	}

	LCDWriteString("Manufacturer:");
	LCDWriteStringXY(0,1,man_id);

	_delay_ms(1000);

	//Manufacturer ID
	LCDClear();

	char model[48];

	r=SIM300GetModel(model);

	if(r==SIM300_TIMEOUT)
	{
		LCDWriteString("Comm Error !");
		Halt();
	}

	LCDWriteString("Model:");
	LCDWriteStringXY(0,1,model);

	_delay_ms(1000);

	//Check Sim Card Presence
	LCDClear();
	LCDWriteString("Checking SIMCard");

	_delay_ms(1000);

	r=SIM300IsSIMInserted();

	if (r==SIM300_SIM_NOT_PRESENT)
	{
		//Sim card is NOT present
		LCDWriteStringXY(0,1,"No SIM Card !");

		Halt();
	}
	else if(r==SIM300_TIMEOUT)
	{
		//Communication Error
		LCDWriteStringXY(0,1,"Comm Error !");

		Halt();
	}
	else if(r==SIM300_SIM_PRESENT)
	{
		//Sim card present
		LCDWriteStringXY(0,1,"SIM Card Present");

		_delay_ms(1000);
	}

	//Network search
	LCDClear();
	LCDWriteStringXY(0,0,"SearchingNetwork");

	uint8_t		nw_found=0;
	uint16_t	tries=0;
	uint8_t		x=0;

	while(!nw_found)
	{
		r=SIM300GetNetStat();

		if(r==SIM300_NW_SEARCHING)
		{
			LCDWriteStringXY(0,1,"%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0");
			LCDWriteStringXY(x,1,"%1");
			LCDGotoXY(17,1);

			x++;

			if(x==16) x=0;

			_delay_ms(50);

			tries++;

			if(tries==600)	
				break;
		}
		else
			break;	

	}
	LCDClear();

	if(r==SIM300_NW_REGISTERED_HOME)
	{
		LCDWriteString("Network Found");
	}
	else
	{
		LCDWriteString("Cant Connt to NW!");
		Halt();
	}

	_delay_ms(1000);

	LCDClear();

	//Show Provider Name
	char pname[32];
	r=SIM300GetProviderName(pname);

	if(r==0)
	{
		LCDWriteString("Comm Error !");
		Halt();
	}

	LCDWriteString(pname);

	_delay_ms(1000);

	Halt();
}

void Halt()
{
	while(1);
}

Steps to configure the AS6 Project

  • Create a new AS6 Project with name “Sim300Demo”.
  • Using solution explorer create a folder named “lib” in current folder.
  • Inside the “lib” folder create the following sub folders “lcd”, “usart” and “sim300”.
  • copy followings files to the lcd folder (using Windows File Manager) lcd.c, lcd.h, myutils.h, custom_char.h
  • copy followings files to the usart folder (using Windows File Manager)usart.c,usart.h
  • copy followings files to the sim300 folder (using Windows File Managersim300.c, sim300.h
  • Add the files lcd.c, lcd.h, myutils.h, custom_char.h to the project using solution explorer.
  • Add the filesusart.c,usart.h to the project using solution explorer.
  • Add the files sim300.c, sim300.h to the project using solution explorer.
  • Define a symbol F_CPU=16000000 using AS6’s
  • In the main application file Sim300Demo.c copy paste the following demo program.
  • Build the project to get the executable hex file.

Download AVRStudio6 project files here: gsm1

Bookmark the permalink.

2 Comments

  1. sir, pls post the link for the sim300.h header file

Comments are closed