Menu

all about electronic and microcontrollers

Monday, July 21, 2014

GSM Click (Temperature & Controll via SMS)

Today I will share with you an experiment made with the module Telit GL856-Quad wich is mounted on a pcb board called "GSM Click Board" designed by Mikroelektronika. The GSM click board is attached to the EasyPIC v7 motherboard trough mikroBUS™ host connector, making our hardware platform.


Telit GL865 Module.

Features:
  1. The Telit GL865-Quad module family can be controlled via the serial interface using the standard AT commands. 
  2. Ultra Compact; GPRS Class 10; LCC Package
  3. Quad Band GSM/GPRS 850/900/1800/1900MHz
  4. Embedded TCP/IP Stack
  5. Supply voltage range: 3.22 - 4.5V DC (3.8V DC recommended)
  6. Power consumption (typical values): Power off: <5 uA
  7. Idle (registered, power saving): 1.5 mA @ DRX=9
  8. Dedicated mode: 230mA @ max power level
  9. GPRS class 10: 360 mA @ max power level
  10. Sensitivity: 108 dBm (typ.) @ 850/900MHz; 106 dBm (typ.) @ 1800/1900MHz.
As can be seen from it's datasheet, the communications are achieved in UART mode (TX,RX), with a Baud rate from 300 to 115,200bps.

Hardware setup:
In example, "FAN1ON" command turns ON the output on RD0, "FAN2OFF" turns OFF the output on RD1. In this experiment we used two leds instead fans (just to prove the output commands.)
PORT RD0 and RD1 leads two digital output and RA0 one analog input.
Some adjustments are needed on Easypic v7 motherboard to establish our connections:
The adjustments are as follow:
  1. Turn on portD LEDs on SW3 (SW3.4).
  2. Place GSM click board into mikroBUS socket 1.
  3. Place power selection jumper (J5) into 3.3V position.





Video:

Pin Configurations.

For hardware details, please study the EasyPic v7 and Telit GL865 datasheets.

Software:
The program is written in mikroC Pro for PIC (version v6.0.0).
Below is my software version:
/*
 * Project name:
    GSM Click (Temperature & Controll via SMS).
 * Copyright:
     Macovei Aureliu Raducu, 2014.
 * Description:
     Program uses GSM module GL865 for sending and receiving SMS.
     The scenario of this experiment is as follows:
     User can interrogate the EasyPIC v7 development board via SMS, and receive
     the status situation of the motherboard.
     Port RD0 and RD1 are used to control two Fans and port RA0 is used to 
     measure the temperature of LM35 sensor.
     As a bonus the temperature is displayed in both format, Celsius and Fahrenheit.
 * Test configuration:
     MCU:             PIC18F45K22
                      http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf
     dev.board:       EasyPIC7
                      http://www.mikroe.com/easypic/
     Oscillator:      HS-PLL 32.0000 MHz, 8.0000 MHz Crystal
     ext. modules:    gsm click : 
                      http://www.mikroe.com/click/gsm/
                      Telit GL865-QUAD
                      http://www.telit.com/en/products.php?p_id=3&p_ac=show&p=110
                      LM35 (Analog temperature sensor)
                      http://www.ti.com/lit/ds/symlink/lm35.pdf
     SW:              mikroC PRO for PIC
                      http://www.mikroe.com/mikroc/pic/
 * NOTES:
     - Due different mobile operators some adjustments may be required, please consult Telit AT commands
       reference guide at http://www.telit.com/module/infopool/download.php?id=542
     - The SMS messages (which GL865 receives) contain commands: "FAN1ON" or "FAN1OFF", "FAN2ON" or "FAN2OFF"
       and "Status?" (it is case sensitive and without quotes).
       In example, "FAN1ON"  command turns ON the output on RD0, "FAN2OFF" turns OFF the output on RD1.
       In this experiment we used two leds instead fans (just to prove the output commands.)
       You can send only the "Status?" inquiry via your SMS (or add it to the SMS containg relay commands) 
       and then you'll receive an info about the state of EasyPic7 motherboard.
       PORT RD0 and RD1 leads two digital output and RA0 one analog input.
       An example of one control message is below:
       "FAN1ON FAN2OFF Status?"  (Note that there is no need for separation chars (spaces in this case)).
       Valid message is also: "FAN2OFFFAN1ONStatus?"; just be careful about the case of letters.

     - Turn on portD LEDs on SW3 (SW3.4).
     - Place GSM click board into mikroBUS socket 1.
     - Place power selection jumper (J5) into 3.3V position.
 */

//  Set VREF according to the voltage reference for LM35:
//  5.00 - power supply jumper set to 5V position (reference = 5V)
//  3.30 - power supply jumper set to 3.3V position (reference = 3.3V)
const unsigned short VREF = 3.30;

// Set of basic AT commands
const char atc0[] = "AT";                        // Every AT command starts with "AT"
const char atc1[] = "ATE0";                      // Disable command echo
const char atc2[] = "AT+CMGF=1";                 // TXT messages
      char atc3[] = "AT+CMGS=\"";                // sends SMS to desired number
const char atc4[] = "AT+CMGR=1";                 // Command for reading message from location 1 from inbox
const char atc5[] = "AT+CMGD=1,4";               // Erasing all messages from inbox
const char atc6[] = "AT+CMGL=\"ALL\"";           // Check status of received SMS
const char atc7[] = "AT#SLED=2";                 // Activate STAT_LED pin
const char atc8[] = "AT#SLEDSAV";                // Save previous command
const char atc9[] = "AT#GPIO=5,0,2";             // Set GPIO5 pin as RFTXMON OUTPUT (the GPIO5 pin is set
                                                 // in output direction; the setting is saved at module power off.)

// Responses to parse
const GSM_OK                       = 0;
const GSM_Ready_To_Receive_Message = 1;
const GSM_ERROR                    = 2;
const GSM_UNREAD                   = 3;
//

// Telit GL865 Module settings
sbit PWRMON at PORTA.B2;
sbit PWRMON_Direction at TRISA2_bit;

sbit RTS at LATE0_bit;
sbit RTS_Direction at TRISE0_bit;

sbit GL865_ON_OFF at LATE1_bit;
sbit GL865_ON_OFF_Direction at TRISE1_bit;
//

//Fan Connections
sbit FAN1 at LATD0_bit;
sbit FAN2 at LATD1_bit;

sbit FAN1_Direction at TRISD0_bit;
sbit FAN2_Direction at TRISD1_bit;
//

// Temperature sensor connections
sbit LM35 at PORTA.B0;
sbit LM35_Direction at TRISA0_bit;
//

// SMS Message string
char SMS_Message[300];

// LM35 data string
char LM35_dataC[15];
char LM35_dataF[15];
//
// phone number string
char phone_number[20];

// State machine control variables
char gsm_state = 0;
char response_rcvd = 0;
short responseID = -1, response = -1;
char gsm_number = 0;
char Unread_flag;
char status_req = 0; // Status request variable

// Send command or data to the Telit GL865 Module - (const)
void GL865_Send(const char *s)
{
// Send command or data string
   while(*s) {
    UART1_Write(*s++);
   }
// Terminatation by CR
   UART_Wr_Ptr(0x0D);
}

// Send command or data to the Telit GL865 Module - (RAM)
void GL865_Send_Ram(char *s1)   //
{
// Send command or data string
   while(*s1) {
    UART_Wr_Ptr(*s1++);
   }
// Terminatation by CR
   UART_Wr_Ptr(0x0D);
}

// Get GSM response, if there is any
short Get_response() {
    if (response_rcvd) {
      response_rcvd = 0;
      return responseID;
    }
    else
      return -1;
}

// Wait for GSM response (infinite loop)
void Wait_response(char rspns) {
char test = 1;

  while (test){
  test = Get_response();
  if ((test == rspns) || (test == GSM_ERROR))
    test = 0;
  else
    test = 1;
  }
}

// Compose Status SMS
unsigned ComposeMessage(char* Message);

// Send Status SMS
void Send_Msg(char* Msg){
  char atc[33];

  atc[0] = 0;                        // clear atc string
  strcat(atc, atc3);                 // atc3 command for sending messages
  strcat(atc, phone_number);         // add phone number
  strcat(atc, "\"");                 // complete AT command
  GL865_Send_Ram(atc);               // send AT command for SMS sending
  Wait_response(GSM_Ready_To_Receive_Message); // Wait for appropriate ready signal

  GL865_Send_Ram(Msg);               // Send message content
  UART_Wr_Ptr(0x1A);                 // Send CTRL + Z as end character
  UART_Wr_Ptr(0x0D);                 // Send CR
  Wait_response(GSM_OK);             // Wait OK as confirmation that the message was sent
}

// Send status SMS to the cell phone number defined by the atc3 const string
void Send_Status(){
 ComposeMessage(SMS_Message);
 Send_Msg(SMS_Message);
}

// 5sec pause
void Wait(){
   Delay_ms(5000);
}

// Main
void main(){
  ANSELA = 0;             // Set all ports as digital
  ANSELB = 0;
  ANSELC = 0;
  ANSELD = 0;
  ANSELE = 0;

  SLRCON = 0;             // Set output slew rate on all ports at standard rate

  ANSELA |= 0x01;         // Configure RA0 pins as analog
  LM35_Direction = 1;     // Configure RA0 pin as input

  //Initialy, FAN's are turned off
  FAN1=0;
  FAN2=0;
  
  FAN1_Direction=0;
  FAN2_Direction=0;
  //

// Setup interrupts
  RC1IE_bit = 1;          // Enable Rx1 intterupts
  PEIE_bit = 1;           // Enable peripheral interrupts
  GIE_bit  = 1;           // Enable global interrupts
//

  // Initial state of Telit GL865 Module pins
  PWRMON_Direction = 1;   // Make PWRMON(RA2) as input

  RTS = 0;                //  Set RTS pin to zero (we will use only RX and TX)
  RTS_Direction  = 0;

  GL865_ON_OFF = 0;
  GL865_ON_OFF_Direction = 0;
  //
  
// Turn on the GM865 module
  GL865_ON_OFF = 1;       // hardware reset
  Delay_ms(2500);         // hold it at least for two seconds
  GL865_ON_OFF = 0;
//

  UART1_Init(9600);
  ADC_Init();

  Wait();                 // Wait a while till the GSM network is configured

// Negotiate baud rate
  while(1) {
    GL865_Send(atc0);                 // Send "AT" string until GSM862 sets up its baud rade
    Delay_ms(100);                    // and gets it correctly
    if (Get_response() == GSM_OK)     // If GSM862 says "OK" on our baud rate we program can continue
      break;
  }

 GL865_Send(atc1);                    // Disable command echo
 Wait_response(GSM_OK);

 GL865_Send(atc2);                    // Set message type as TXT
 Wait_response(GSM_OK);
 
 GL865_Send(atc7);                    // Activate STAT_LED pin
 Wait_response(GSM_OK);
 
 GL865_Send(atc8);                    // Then save it
 Wait_response(GSM_OK);
 
 GL865_Send(atc9);                    // Set GPIO5 pin as RFTXMON OUTPUT
 Wait_response(GSM_OK);

 while(1){
   GL865_Send(atc5);             // Delete all messages (if any)
   if (get_response() == GSM_OK) // If messages are deleted
     break;                      // break from while
   Delay_ms(500);
 }
  // infinite loop
  while(1) {
    GL865_Send(atc6);        // Read status of the messages and read message it self
    Delay_ms(100);           // Wait until the message is read

    while(1) {
      GL865_Send(atc0);      // Wait until the module is ready
      Delay_ms(50);
      if (Get_response() == GSM_OK)
        break;
    }
    
    if (Unread_flag){
      while(1) {
        GL865_Send(atc0);    // Wait until the module is ready
        Delay_ms(50);
        if (Get_response() == GSM_OK)
          break;
      }

      if (status_req){       // Send status SMS if it's been requested
        status_req = 0;
        Send_Status();
      }

      Unread_flag = 0;
    }

    while(1){
      GL865_Send(atc5);  // Delete all messages (if any)
      Delay_ms(50);
      if (get_response() == GSM_OK) // If messages are deleted
        break;           // break from while
      Delay_ms(50);
      if (Unread_flag){  // if we have received message in mean time
        Unread_flag = 0;
        break;           // break from while
      }
    }
    Wait();
  }
}

/******************************************************************************/

// Compose Status SMS
unsigned ComposeMessage(char* Message){
  unsigned int adc_value1 = 0;
  float Celsius_format, Fahrenheit_format;
 
  RC1IE_bit = 0;                // Disable Rx1 intterupts

  Message[0] = '\0';
//================================================================
  // SMS header
  strcat(Message, "EasyPIC7 Info:");
  strcat(Message, "\r\n");              // Add new line (CR + LF)
  //
  if(FAN1)
     strcat(Message, "FAN1: ON");
  else
     strcat(Message, "FAN1: OFF");
  strcat(Message, "\r\n");              // Add new line (CR + LF)
  
  if(FAN2)
     strcat(Message, "FAN2: ON");
  else
     strcat(Message, "FAN2: OFF");
  strcat(Message, "\r\n");              // Add new line (CR + LF)
//================================================================

  // Adding Temperature values to the SMS
  adc_value1 = ADC_Get_Sample(0);                 // RA0
  Celsius_format = (adc_value1 * VREF)/10.240;    // Calculate temperature in Celsuis
  FloatToStr(Celsius_format, LM35_dataC);
  LM35_dataC[4] =0;                               // Use just four string value

  strcat(Message, "TEMP: +");
  strcat(Message, LM35_dataC);
  strcat(Message, "'C");                          // Celsius degree symbol
  strcat(Message, " / +");                        // Delimitation and + symbol
  
  Fahrenheit_format = (Celsius_format *9/5)+32;   // °F =°C*9/5 + 32 transformation formula
  FloatToStr(Fahrenheit_format, LM35_dataF);
  LM35_dataF[4] =0;                               // Use just four string value
  strcat(Message, LM35_dataF);
  strcat(Message, "'F");
  strcat(Message, "\r\n");                        // Add new line (CR + LF)
  // SMS footer
  strcat(Message, "End.");
  strcat(Message, "\r\n");                        // Add new line (CR + LF)
  //
  RC1IE_bit = 1;                                  // Enable Rx1 intterupts

  return strlen(Message);
}

// state machine
// Reading the data from UART in the interuppt routine
void interrupt(){
char tmp,i;

  if (RCIF_bit == 1) {                           // Do we have uart rx interrupt request?
    tmp = UART_Rd_Ptr();                         // Get received byte

// Process reception through state machine
// We are parsing only "OK" and "> " responses
    switch (gsm_state) {
      case  0: {
                response = -1;                   // Clear response
                if (tmp == 'O')                  // We have 'O', it could be "OK"
                  gsm_state = 1;                 // Expecting 'K'
                if (tmp == '>')                  // We have '>', it could be "> "
                  gsm_state = 10;                // Expecting ' '
                if (tmp == 'E')                  // We have 'E', it could be "> "
                  gsm_state = 30;                // Expecting 'R'
                if (tmp == 'S')                  // We have 'S', it could be "Status?"
                  gsm_state = 40;                // Expecting 't'
                if (tmp == 'F')                  // We have 'F', it could be "FANxON or FANxOFF"
                  gsm_state = 50;                // Expecting A
                if (tmp == 'U')                  // We have 'U', it could be "UNREAD"
                  gsm_state = 70;                // Expecting 'N'
                break;
               }
      case  1: {
                if (tmp == 'K') {                // We have 'K' ->
                  response = GSM_OK;             // We have "OK" response
                  gsm_state = 20;                // Expecting CR+LF
                }
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 10: {
                if (tmp == ' ') {
                  response_rcvd = 1;             // We have "> " response
                  response = GSM_Ready_To_Receive_Message; // Set reception flag
                  responseID = response;         // Set response ID
                }
                gsm_state = 0;                   // Reset state machine
                break;
                }

      case 20: {
                if (tmp == 13)                   // We have 13, it could be CR+LF
                  gsm_state = 21;                // Expecting LF
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 21: {
                if (tmp == 10) {                 // We have LF, response is complete
                  response_rcvd = 1;             // Set reception flag
                  responseID = response;         // Set response ID
                }
                gsm_state = 0;                   // Reset state machine
                break;
               }

      case 30: {
                if (tmp == 'R')                  // We have 'R', it could be "ERROR"
                  gsm_state = 31;                // Expecting 'R'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 31: {
                if (tmp == 'R')                  // We have 'R', it could be "ERROR"
                  gsm_state = 32;                // Expecting 'O'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 32: {
                if (tmp == 'O')                  // We have 'O', it could be "ERROR"
                  gsm_state = 33;                // Expecting 'R'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 33: {
                if (tmp == 'R'){                 // We have 'R'
                  response_rcvd = 1;             // We have "ERROR" response
                  response = GSM_ERROR;          // Set reception flag
                  responseID = response;         // Set response ID
                }
                gsm_state = 0;                   // Reset state machine
                break;
                }
      case 40: {
                if (tmp == 't')                  // We have 't', it could be "Status?"
                  gsm_state = 41;                // Expecting 'a'
                else
                  gsm_state = 0;               // Reset state machine
                break;
                }
      case 41: {
                if (tmp == 'a')                  // We have 'a', it could be "Status?"
                  gsm_state = 42;                // Expecting 't'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 42: {
                if (tmp == 't')                  // We have 't', it could be "Status?"
                  gsm_state = 43;                // Expecting 'u'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 43: {
                if (tmp == 'u')                  // We have 'u', it could be "Status?"
                  gsm_state = 44;                // Expecting 's'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 44: {
                if (tmp == 's')                  // We have 's', it could be "Status?"
                  gsm_state = 45;                // Expecting '?'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 45: {
                if (tmp == '?'){                 // We have '?'
                  status_req = 1;                // Status has been requested!
                }
                gsm_state = 0;                   // Reset state machine
                break;
                }

      case 50: {
                if (tmp == 'A')                  // We have 'A', it could be "FANx"
                  gsm_state = 51;                // Expecting 'N'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 51: {
                if (tmp == 'N')                  // We have 'N', it could be "FANx"
                  gsm_state = 52;                // Expecting number
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 52: {
                if (tmp == '1')
                   gsm_state = 53;
                else
                if (tmp == '2')
                   gsm_state = 60;
                else
                   gsm_state = 0;
                break;
                }
                
      case 53: {
                if (tmp == 'O')
                gsm_state = 54;
                else
                gsm_state = 0;
                break;
               }
               
      case 54: {
                if (tmp == 'N'){
                   FAN1 = 1;
                   gsm_state = 0;}
                else
                if (tmp == 'F')
                   gsm_state = 55;
                else
                   gsm_state = 0;
                break;
               }
      case 55: {
                if (tmp == 'F'){
                   FAN1 = 0;
                   gsm_state = 0;}
                else
                   gsm_state = 0;
                break;
                }
      case 60: {
                if (tmp == 'O')
                   gsm_state = 61;
                else
                   gsm_state = 0;
                break;
                }
      case 61: {
                if (tmp == 'N'){
                   FAN2 = 1;
                   gsm_state = 0;}
                else
                   if (tmp = 'F')
                   gsm_state = 62;
                else
                   gsm_state = 0;
                break;
                }
      case 62: {
                if (tmp == 'F'){
                   FAN2 = 0;
                   gsm_state = 0;}
                else
                   gsm_state = 0;
                break;
                }
      case 70: {
                if (tmp == 'N')
                   gsm_state = 71;
                else
                   gsm_state = 0;
                break;
                }
      case 71: {
                if (tmp == 'R')
                   gsm_state = 72;
                else
                   gsm_state = 0;
                break;
                }
      case 72: {
                if (tmp == 'E')
                   gsm_state = 73;
                else
                   gsm_state = 0;
                break;
                }
      case 73: {
                if (tmp == 'A')
                   gsm_state = 74;
                else
                   gsm_state = 0;
                break;
                }
      case 74: {
                if (tmp == 'D'){
                   response_rcvd = 1;             // We have "ERROR" response
                   response = GSM_UNREAD;         // Set reception flag
                   responseID = response;         // Set response ID
                   Unread_flag = 1;
                   }
                gsm_state = 0;
                break;
                }
      default: {                                 // Unwanted character
                gsm_state = 0;                   // Reset state machine
               }
    }
    // parse phone number on which we should reply
    switch (gsm_number) {
      case 0 :{
               if (tmp == '"'){
                 gsm_number = 1;
                 i = 0;
               }
              }; break;
      case 1 :{
               if (tmp == '+'){
                 phone_number[i] = tmp;
                 i ++;
                 gsm_number = 2;
               }
               else{
                 gsm_number = 0;
                 i = 0;
               }
              }; break;
      case 2 :{
               if (tmp >= '0' && tmp <= '9'){
                 phone_number[i] = tmp;
                 i ++;
               }
               else
                 if (tmp == '"'){
                   phone_number[i] = 0;
                   i = 0;
                   gsm_number = 0;
                 }
                 else{
                   phone_number[0] = 0;
                   i = 0;
                   gsm_number = 0;
                 }
              }; break;
      default : {
                 phone_number[0] = 0;
                 i = 0;
                 gsm_number = 0;
                }
    }
 }
}
/******************************************************************************/

12 comments:

  1. its really intresting post, keep posting
    thanks for sharing your Thought

    ReplyDelete
  2. hi, would you mind to post the body of UART_Wr_Ptr(). Thx and good keep up the good work :-)

    ReplyDelete
    Replies
    1. Hi,
      When you do UART1_Init(), you set UART_Rd_Ptr and UART_Wr_Ptr. These are read and write pointers and function from libraries are calling Uart functions through those pointers.

      Delete
  3. hi can you provide this code via email or link want to check my gsm modem.

    thanks in advance

    ReplyDelete
  4. Hi,
    I would appreciate it if you can help me with my project please.
    I am using the easypicV7 too and a GSM module able to send and receive SMS.
    I don't know how to configure the GSM to send and receive messages ( I read the comments on your code and they did help me) but I still do not know where to enter the phone number I want to send the SMS to.

    Thank you.

    ReplyDelete
  5. Not working on my easypicv7 board with similar setup except on my network provider in PH

    ReplyDelete
    Replies
    1. Hi there,
      to compile the code, you need the genuine version of mikroc compiler.

      Delete
  6. That's an interesting experiment. Your blog shows the growth of Embedded Software Development . Thank you for also sharing the code you used for the experiment.

    ReplyDelete
  7. Thanks for Sharing!!

    At George Stevens Manufacturing, we specialize in producing high-quality transformer coil winding machines. We are committed to providing innovative solutions that meet each of our client's unique needs. We offer a wide range of winding machines, from hand-operated models to fully automated systems, and our team can work with clients to develop custom solutions that meet their specific needs. For more information, visit the website!!

    ReplyDelete
  8. Thanks for Sharing!!

    Illini Foundry is a premier impeller castings manufacturer for a wide range of industrial applications. The impellers produced by Illini Foundry are known for their precision and durability. These castings are used in a variety of equipment, including pumps, compressors, and turbines, and are designed to operate in harsh and demanding environments. For more information, visit the website!!

    ReplyDelete

If you do not understand something, or if you make some aplication helped by this blog, let me know.