Go Down

Topic: Arduino using GSM Siemens TC35i (Read 10 times) previous topic - next topic

dan007

Good afternokn guys.
Long overdue latest update. I am having great success the tc35i using the above code + some tweeks. However I'm rather stuck in tackling a problem with this code. When I attach my other functions temperate reading, setting and LCD updates, because of the delays used it misses the incoming message signal.
Is there any way to attach an interrupt with the serial? Or am I looking down the wrong path.

I basically need the program to constantly monitor temperature readings and display them on the LCD. But in doing this the software misses the moment the serial recieves the new message command.

Any help is much appreciated guys, if you need any further information or my latest could just let me know.

Regard
Dan
Never Assume;
As it makes an ASS out of U & ME

HugoPT

Quote
When I attach my other functions temperate reading, setting and LCD updates, because of the delays used it misses the incoming message signal.

It should not be missed since it will stay in serial port buffer waiting to be read.You must insure you are "looking" in your loop if there is something to read (if (Serial.available())  and if there is something read it to prevent Serial buffer overflow.
Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

dan007

Thank you for the prompt response Hugo.
From my understanding/small experience so far, if the programming is calculating something in a loop. The serial.available misses the transmission as it isn't being called for looked at whilst in a processing loop. Does the serialevent function manage to capture serial data received whilst processing something else?

In a nutshell I need to capture serial command (+CMTI) sent by the GSM modem which alerts a received SMS. The code earlier in this thread works as a live serial stream, but not whilst processing something.

Kind regards Dan.

P.s would you like to see the full latest code I have so far?
Never Assume;
As it makes an ASS out of U & ME

HugoPT

Quote
Does the serialevent function manage to capture serial data received whilst processing something else?

Yes.The serial interface still received data while the cpu is doing another things, and will put the incoming bytes in a Serial buffer to be read in a near future.This buffer has a limit and if you don't read it, it will  overflow and you loose data.
Quote
P.s would you like to see the full latest code I have so far?

Yes post the code to stay in sync with you
Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

dan007

No problem, I'll shall makes sure the code is tidy and has the relevant comments when I get in from work later and post the update.
Regards
Never Assume;
As it makes an ASS out of U & ME

dan007

Code: [Select]

/*
Process incoming serial data without blocking by Nick Gammon
http://gammon.com.au/serial
The rest of the sketch is by me

AT+CMGF=1          for txt mode
AT+CNMI=2,1,0,0,1  message indication
AT^SMGO=1          SMS full indication
AT&W               store to memory

To check what you have entered
AT&V               display current configuration

*/

#include <SoftwareSerial.h>
SoftwareSerial gsmSerial(9,10);  //Creates a software serial port. (rx,tx) using the software serial header file

//-------- TC35i GSM ---------------
int SMS_location_number;
const unsigned int MAX_INPUT = 165; // 160 characters for SMS plus a few extra
static unsigned int input_pos = 0;

float TempSens;  // temperature array for the 2 readings
int TempAver;     // average temp of 2 internal sensors
float Voltage;
int TempDisplay;
int Setting;

//------ Inital setup ----------
void setup()
{
  //Set I/O status
  pinMode(13, OUTPUT); //Test output
  pinMode(12, OUTPUT); //Drive to relay
 
  Serial.begin(9600);         //Start default serial for LCD screen and debug
  gsmSerial.begin(9600);      //Starts addtional serial port for GSM
  delay(10);                  //10ms delay
 
  brightness();               //Set brightness by runing brightness function
  clearLCD();                 //Clear LCD from setup data by using clearLCD function
 
  WelcomeMessage();           //Step 01 :- Welcome splash screen (defined in WelcomeMessage function)
  GSM_Startup();              //Step 02 :- Run the GSM start function
  System_Healthy();           //Step 03 :- Setup no complete
 
}
//------ End setup -------

//------ Main loop -------
void loop()   
{
  readTC35i();                //Step 04 :- Run through TC35i for incomming message
  TempSetting();              //Step 05 :- Run temperature function to get temperatures
  TempFunction();             //Step 06 :- Run temperature function to get temperatures
 
  selectLineOne();
  Serial.write("Temp = ");
  Serial.print(TempDisplay);
  Serial.write("c  ");

  selectLineTwo(); 
  Serial.write("Setting = ");
  Serial.print(Setting);
  Serial.write("c  ");
  delay(1500);
 
}
//------ End loop --------

//---------------------------- Read TC35i ------------------------------------//

// Read data from the TC35i, When a linefeed is read the data is processed

void readTC35i()
{
  static char input_line [MAX_INPUT];    //static unsigned int input_pos = 0;
  if (gsmSerial.available () > 0) //
  {
    while (gsmSerial.available () > 0)
    {
      char inByte = gsmSerial.read ();
      switch (inByte)
      {

      case '\n':   // end of text
        input_line [input_pos] = 0;  // terminating null byte

        // terminator reached! process input_line here ...
        process_data (input_line);

        // reset buffer for next time
        input_pos = 0; 
        break;

      case '\r':   // discard carriage return
        break;

      default:
        // keep adding if not full ... allow for terminating null byte
        if (input_pos < (MAX_INPUT - 1))
          input_line [input_pos++] = inByte;
        break;

      }  // end of switch
    }  // end of while incoming data
  }  // end of if incoming data
}  // end of readTC35i



//---------------------------- process_data --------------------------------

void process_data (char * data)
{
    //Serial.println (data); // display the data

  if(strstr(data, "+CMGR:") && strstr(data, "+44XXXXXXXXXX"))
  { 
    // Reads the +CMGR line to check if SMS is from a known Phone number
    // This if statement could cover the whole of the process_data function
    // then only known a phone number could control the Arduoino
  }

  if(strstr(data, "smsdelete"))
  {
    delete_All_SMS();
  }

  if(strstr(data, "^SMGO: 2"))
  { // SIM card FULL
    delete_All_SMS();           // delete all SMS
  }

  if(strstr(data, "+CMTI:"))
  {    // An SMS has arrived
    char* copy = data + 12;      // Read from position 12 until a non ASCII number to get the SMS location
    SMS_location_number = (byte) atoi(copy);  // Convert the ASCII number to an int
    gsmSerial.print("AT+CMGR=");
    gsmSerial.println(SMS_location_number);  // Print the SMS in Serial Monitor
  }                                          // this SMS data will go through this process_data function again
  // any true if statements will execute

  if(strstr(data, "Heating on")) // If data contains Heating on
  {   
       
    digitalWrite(13, HIGH);    // REPLACE THIS WITH RELAY CONNECTION
    selectLineTwo();
    Serial.write("Heating is on");
    delay(100);
    gsmSerial.print("AT+CMGS=+44XXXXXXXXXX\r"); //AT command to send SMS
    delay(100);
    gsmSerial.print("Heating is now switched on"); //Print the message
    delay(10);
    gsmSerial.print("\x1A"); //Send it ascii SUB
    delay(10);
    delete_one_SMS();  //Calls delete message function
  }

  if(strstr(data, "Heating off"))
  {
    digitalWrite(13, LOW);    // REPLACE THIS WITH RELAY CONNECTION
    selectLineTwo();
    Serial.write("Heating is off");
    delay(100);     
    gsmSerial.print("AT+CMGS=+44XXXXXXXXXX\r"); //AT command to send SMS
    delay(100);
    gsmSerial.print("Heating is now switched off"); //Print the message
    delay(10);
    gsmSerial.print("\x1A"); //Send it ascii SUB
    delay(10);
    delete_one_SMS(); //Calls delete message function
  }

}  //--------------------------- end of process_data ---------------------------

void delete_one_SMS()
{
  clearLCD();
  selectLineTwo();
  Serial.write("deleting SMS ");
  Serial.print("1");
  gsmSerial.print("AT+CMGD=");
  gsmSerial.println("1");
  delay(1000);
}

void delete_All_SMS()
{
  for(int i = 1; i <= 10; i++) {
    gsmSerial.print("AT+CMGD=");
    gsmSerial.println(i);
    selectLineTwo();
    Serial.write("deleting SMS ");
    Serial.print(i);
    delay(500);
  }
}

void clearLCD()
{ //clears the LCD display
  Serial.write(0xFE); //command flag
  Serial.write(0x01); //clear command.
  delay(50);
}

void brightness()
{ //clears the LCD display
  Serial.write(0x7C); //command flag
  Serial.write(148); //brightness level.
  delay(50);
}

void WelcomeMessage()
{
  selectLineOne();
    Serial.write("A greener home");
  selectLineTwo();
    Serial.write("Loading...");
    delay(1500); 
  clearLCD(); // Clear LCD funtion
  selectLineOne();
    Serial.write("TC35i Start up");
  selectLineTwo();
    Serial.write("Configuring...");
    delay(1500);   
}

void GSM_Startup()
{
  gsmSerial.print("AT+CMGF=1\r");
  delay(100);
  gsmSerial.print("AT+CNMI=2,1,0,0,1\r");
  delay(100); 
  delete_All_SMS();
}

void System_Healthy()
{
  clearLCD(); // Clear LCD funtion
  selectLineOne();
    Serial.write("System healthy");
    delay(1000);
   clearLCD();
}

void selectLineOne()
{ //puts the cursor at line 0 char 0.
  Serial.write(0xFE); //command flag
  Serial.write(128); //position
}
                                                                   
void selectLineTwo()
{ //puts the cursor at line 1 char 0.
  Serial.write(0xFE); //command flag
  Serial.write(192); //position
}

void TempFunction()
{
   int count = 0;                          // counter set to 0
   while (count <= 9){                     // while loop to log each temperature reading
     float reading = analogRead(1);      //getting the voltage reading from the temperature sensor
     Voltage = ((reading * 5)/1024);          // converting that reading to voltage           
     float temperatureC = (Voltage - 0.5) * 100 ;  //converting from 10 mv per degree wit 500 mV offset to degrees ((voltage - 500mV) times 100)
     TempAver = (TempAver + temperatureC);     // log the temperature in the array
     count++;     
   }
   TempAver = (TempAver / 10);  // calculates the average of the 2 sensors
   TempDisplay = TempAver;
}

void TempSetting()
{
  // read the input on analog pin 0:
  float sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Setting = (15 + (voltage/0.5));
  delay(100);
}
Never Assume;
As it makes an ASS out of U & ME

HugoPT

#21
Mar 06, 2014, 10:19 am Last Edit: Mar 06, 2014, 10:35 am by HugoPT Reason: 1
What arduino board are you using?
I ask this because of this:
Quote

#include <SoftwareSerial.h>
SoftwareSerial gsmSerial(9,10);  //Creates a software serial port. (rx,tx) using the software serial header file

In lot of boards pin 9 does not support interrupts and the rx event e captured using an interrupt caused on the RX pin.
You have a strong probability that your pin 9 does not support interrupts unless you are using the DUE board
See here the pins that support interrupts
Quote
http://arduino.cc/en/Reference/attachInterrupt#.UxhC8GchhCI
Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

dan007

I have the Arduino Uno R3 model for test and development, but for my project build I have also made my ow using the same ATmega328 on stripboard.

Regards.
Never Assume;
As it makes an ASS out of U & ME

HugoPT

Quote
have the Arduino Uno R3 model for test and development,

So this confirms your pin 9 does not support interrupts
Change the softwareserial to :
Quote
SoftwareSerial gsmSerial(2,3);  //Creates a software serial port. (rx,tx) using the software serial header file
Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

dan007

I see that changing the pins to 2,3 will place them on the interrupt pins. However won't I still need to recode the readTC35i fucntion, as a  serialevent()?

Regards.
Never Assume;
As it makes an ASS out of U & ME

HugoPT

Just change the pins and test the existing code you have
Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

dan007

I shal try your solution when I get in tonight, but I'm sure I've used 2&3 before in this setup before moving to 9,10. But haven't used anything like the serialevent.

Regards
Never Assume;
As it makes an ASS out of U & ME

HugoPT

Also I think you forgot to put the softwareserial listening so you need to add this:
Quote

  Serial.begin(9600);         //Start default serial for LCD screen and debug
  gsmSerial.begin(9600);      //Starts addtional serial port for GSM
  gsmSerial.listen(); //Put the serial port in listen
  delay(10);                  //10ms delay
Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

dan007

Thanks for the Advice given so far, but the solution was far simpler than anticpated as I was (we was) look to far outside the box.
The key was to remove the delays i.e. delay(1500); and use the implement the blink without delay method for the LCD updates.
Giving LCD updates every 1000millis, and still processing everything else.

Thanks again for your effort, below is the revised code.  :smiley-mr-green:

Code: [Select]

/*
Process incoming serial data without blocking by Nick Gammon
http://gammon.com.au/serial
The rest of the sketch is by me

AT+CMGF=1          for txt mode
AT+CNMI=2,1,0,0,1  message indication
AT^SMGO=1          SMS full indication
AT&W               store to memory

To check what you have entered
AT&V               display current configuration

*/

#include <SoftwareSerial.h>
SoftwareSerial gsmSerial(9,10);  //Creates a software serial port. (rx,tx) using the software serial header file

//-------- TC35i GSM ---------------
int SMS_location_number;
const unsigned int MAX_INPUT = 165; // 160 characters for SMS plus a few extra
static unsigned int input_pos = 0;

float TempSens;  // temperature array for the 2 readings
int TempAver;     // average temp of 2 internal sensors
float Voltage;
int TempDisplay;
int Setting;

int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

long interval = 1000;           // interval at which to blink (milliseconds)



//------ Inital setup ----------
void setup()
{
  //Set I/O status
  pinMode(13, OUTPUT); //Test output
  pinMode(12, OUTPUT); //Drive to relay
 
  Serial.begin(9600);         //Start default serial for LCD screen and debug
  gsmSerial.begin(9600);      //Starts addtional serial port for GSM
  delay(10);                  //10ms delay
 
  brightness();               //Set brightness by runing brightness function
  clearLCD();                 //Clear LCD from setup data by using clearLCD function
 
  WelcomeMessage();           //Step 01 :- Welcome splash screen (defined in WelcomeMessage function)
  GSM_Startup();              //Step 02 :- Run the GSM start function
  System_Healthy();           //Step 03 :- Setup no complete
 
}
//------ End setup -------

//------ Main loop -------
void loop()   
{
  readTC35i();                //Step 04 :- Run through TC35i for incomming message
  TempSetting();              //Step 05 :- Run temperature function to get temperatures
  TempFunction();             //Step 06 :- Run temperature function to get temperatures


unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval)
  {
    previousMillis = currentMillis;   

  selectLineOne();
  Serial.write("Temp = ");
  Serial.print(TempDisplay);
  Serial.write("c  ");

  selectLineTwo(); 
  Serial.write("Setting = ");
  Serial.print(Setting);
  Serial.write("c  ");
  } 
}
//------ End loop --------

//---------------------------- Read TC35i ------------------------------------//

// Read data from the TC35i, When a linefeed is read the data is processed

void readTC35i()
{
  static char input_line [MAX_INPUT];    //static unsigned int input_pos = 0;
  if (gsmSerial.available () > 0) //
  {
    while (gsmSerial.available () > 0)
    {
      char inByte = gsmSerial.read ();
      switch (inByte)
      {

      case '\n':   // end of text
        input_line [input_pos] = 0;  // terminating null byte

        // terminator reached! process input_line here ...
        process_data (input_line);

        // reset buffer for next time
        input_pos = 0; 
        break;

      case '\r':   // discard carriage return
        break;

      default:
        // keep adding if not full ... allow for terminating null byte
        if (input_pos < (MAX_INPUT - 1))
          input_line [input_pos++] = inByte;
        break;

      }  // end of switch
    }  // end of while incoming data
  }  // end of if incoming data
}  // end of readTC35i



//---------------------------- process_data --------------------------------

void process_data (char * data)
{
    //Serial.println (data); // display the data

  if(strstr(data, "+CMGR:") && strstr(data, "+44XXXXXXXXXX"))
  { 
    // Reads the +CMGR line to check if SMS is from a known Phone number
    // This if statement could cover the whole of the process_data function
    // then only known a phone number could control the Arduoino
  }

  if(strstr(data, "smsdelete"))
  {
    delete_All_SMS();
  }

  if(strstr(data, "^SMGO: 2"))
  { // SIM card FULL
    delete_All_SMS();           // delete all SMS
  }

  if(strstr(data, "+CMTI:"))
  {    // An SMS has arrived
    char* copy = data + 12;      // Read from position 12 until a non ASCII number to get the SMS location
    SMS_location_number = (byte) atoi(copy);  // Convert the ASCII number to an int
    gsmSerial.print("AT+CMGR=");
    gsmSerial.println(SMS_location_number);  // Print the SMS in Serial Monitor
  }                                          // this SMS data will go through this process_data function again
  // any true if statements will execute

  if(strstr(data, "Heating on")) // If data contains Heating on
  {         
    digitalWrite(13, HIGH);    // REPLACE THIS WITH RELAY CONNECTION
    selectLineTwo();
    Serial.write("Heating is on");
    delay(100);
    gsmSerial.print("AT+CMGS=+447726222272\r"); //AT command to send SMS
    delay(100);
    gsmSerial.print("Heating is now switched on"); //Print the message
    delay(10);
    gsmSerial.print("\x1A"); //Send it ascii SUB
    delay(10);
    delete_one_SMS();  //Calls delete message function
  }

  if(strstr(data, "Heating off"))
  {
    digitalWrite(13, LOW);    // REPLACE THIS WITH RELAY CONNECTION
    selectLineTwo();
    Serial.write("Heating is off");
    delay(100);     
    gsmSerial.print("AT+CMGS=+447726222272\r"); //AT command to send SMS
    delay(100);
    gsmSerial.print("Heating is now switched off"); //Print the message
    delay(10);
    gsmSerial.print("\x1A"); //Send it ascii SUB
    delay(10);
    delete_one_SMS(); //Calls delete message function
  }

}  //--------------------------- end of process_data ---------------------------

void delete_one_SMS()
{
  clearLCD();
  selectLineTwo();
  Serial.write("deleting SMS ");
  Serial.print("1");
  gsmSerial.print("AT+CMGD=");
  gsmSerial.println("1");
  delay(1000);
}

void delete_All_SMS()
{
  for(int i = 1; i <= 10; i++) {
    gsmSerial.print("AT+CMGD=");
    gsmSerial.println(i);
    selectLineTwo();
    Serial.write("deleting SMS ");
    Serial.print(i);
    delay(500);
  }
}

void clearLCD()
{ //clears the LCD display
  Serial.write(0xFE); //command flag
  Serial.write(0x01); //clear command.
  delay(50);
}

void brightness()
{ //clears the LCD display
  Serial.write(0x7C); //command flag
  Serial.write(148); //brightness level.
  delay(50);
}

void WelcomeMessage()
{
  selectLineOne();
    Serial.write("A greener home");
  selectLineTwo();
    Serial.write("Loading...");
    delay(1500); 
  clearLCD(); // Clear LCD funtion
  selectLineOne();
    Serial.write("TC35i Start up");
  selectLineTwo();
    Serial.write("Configuring...");
    delay(1500);   
}

void GSM_Startup()
{
  gsmSerial.print("AT+CMGF=1\r");
  delay(100);
  gsmSerial.print("AT+CNMI=2,1,0,0,1\r");
  delay(100); 
  delete_All_SMS();
}

void System_Healthy()
{
  clearLCD(); // Clear LCD funtion
  selectLineOne();
  Serial.write("System healthy");
  delay(1000);
  clearLCD();
}

void selectLineOne()
{ //puts the cursor at line 0 char 0.
  Serial.write(0xFE); //command flag
  Serial.write(128); //position
}
                                                                   
void selectLineTwo()
{ //puts the cursor at line 1 char 0.
  Serial.write(0xFE); //command flag
  Serial.write(192); //position
}

void TempFunction()
{
   int count = 0;                          // counter set to 0
   while (count <= 9){                     // while loop to log each temperature reading
     float reading = analogRead(1);      //getting the voltage reading from the temperature sensor
     Voltage = ((reading * 5)/1024);          // converting that reading to voltage           
     float temperatureC = (Voltage - 0.5) * 100 ;  //converting from 10 mv per degree wit 500 mV offset to degrees ((voltage - 500mV) times 100)
     TempAver = (TempAver + temperatureC);     // log the temperature in the array
     count++;     
   }
   TempAver = (TempAver / 10);  // calculates the average of the 2 sensors
   TempDisplay = TempAver;
}

void TempSetting()
{
  // read the input on analog pin 0:
  float sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Setting = (15 + (voltage/0.5));
}
Never Assume;
As it makes an ASS out of U & ME

HugoPT

#29
Mar 06, 2014, 10:54 pm Last Edit: Mar 06, 2014, 10:58 pm by HugoPT Reason: 1
I'm glad you make it but now I'm very confused with somethings that if possible I like to discuss with you.
You told you are using the Arduino Uno R3 but in your code you again have RX pin 9 which clearly does not support interrupts
So how can your code work?
Are you sure if you upload that, does it still work?
About the delays, in general using delays are a bad practice so you have done a good move replacing delays with   millis().
But even if you have a gigantic delay like 20 seconds the data is still captured because the virtual serial port  will fire an interrupt for every byte it gets and place it in serial buffer.
So the conclusion is, even using delays you will not loose those incoming bytes!
I had prepared a small test to prove that.

Code: [Select]

#include <SoftwareSerial.h>
#define BIG_DELAY 10000UL
SoftwareSerial mySerial(2, 3); // RX, TX

void setup()
{
 Serial.begin(9600);
 mySerial.begin(9600);
 Serial.println("Testing Virtual Serial port with a big delay");
}
void loop()
{
 Serial.println("Starting delay for 10 seconds.Send me some data now while I'm doing nothing");
 delay(BIG_DELAY);
 while(mySerial.available()){
   char a = mySerial.read();
   Serial.print(a);
 }
}

I connect my ftdi232 interface TX pin to arduino pin 2 and when it enters in the delay for 10 seconds I start send the data.After the 10 seconds has passed I get printed all the bytes I had entered, probing I don't lose nothing even when my chip was running a delay(a nop operation).
Debian,Mint,Ubuntu
Arduino Mega 2560
Arduino Nano
Arduino Duemilanove
MAC OS Montain Lion
Raspberry PI Model B

Go Up