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:
- The Telit GL865-Quad module family can be controlled via the serial interface using the standard AT commands.
- Ultra Compact; GPRS Class 10; LCC Package
- Quad Band GSM/GPRS 850/900/1800/1900MHz
- Embedded TCP/IP Stack
- Supply voltage range: 3.22 - 4.5V DC (3.8V DC recommended)
- Power consumption (typical values): Power off: <5 uA
- Idle (registered, power saving): 1.5 mA @ DRX=9
- Dedicated mode: 230mA @ max power level
- GPRS class 10: 360 mA @ max power level
- 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:
- 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.
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;
}
}
}
}
/******************************************************************************/