Disturbing Signal

Hi guys, I'm having a problem for my project about Arduino and GSM SIM900A
My project is to monitoring the electricity usage for house appliances through SMS. The pulse is get from the energy meter through interrupt method and calculate with arduino. Supposedly I should get the results from the serial monitor when i send the command "check" to check the usage and cost, but it seems that the GSM can't receive the signal because of loop disturbing the signal. Can anyone know how to solve the problem?

#include <LiquidCrystal.h>
#include "EmonLib.h"
#include <SoftwareSerial.h>
SoftwareSerial SIM900A(7, 8);
LiquidCrystal lcd(12, 11, 5, 4, 6, 2);
EnergyMonitor emon1; 

int pulse;
long pulseCount = 0;                              //Number of pulses, used to measure energy.
unsigned long pulseTime,lastTime;                 //Used to measure power.
double power, elapsedkWh;                         //power and energy
char inchar;                                      //Will hold the incoming character from the Serial Port.
int led = 8;
int relay = 7;
char incoming_char=0;
char temp[60];
int m=0;
float TBill = 0.0;
float realPower= 0.0;
float IBill = 0.00;
int ppwh = 1;                                     //Number of pulses per wh - found or set on the meter.
                                                  //1000 pulses/kwh = 1 pulse per wh 

 
void setup()
{ 
  SIM900A.begin(19200);
  Serial.begin(19200);                             // Setting the baud rate of Serial Monitor (Arduino)
  delay(10000);                                    // give time to log on to network.
 
  SIM900A.print("AT+CMGF=1\r");                    // set SMS mode to text
  delay(100);
  SIM900A.print("AT+CNMI=2,2,0,0,0\r"); 
  // blurt out contents of new SMS upon receipt to the GSM shield's serial out
  delay(100);
  attachInterrupt(1, onPulse, FALLING);             // KWH interrupt attached to IRQ 1 = pin3
  emon1.current(1, 20);  
  pinMode(pulse, INPUT);
  
}

 
void loop()
{
  
  m=0;
  
  for (int m=0;m<60;m++)
  {
  if(SIM900A.available() >0)
  {
    incoming_char=SIM900A.read();                   //Get the character from the cellular serial port.
    Serial.print(incoming_char);                   //Print the incoming character to the terminal.
    
    if(inchar=='0')
      {
        delay(10);
        inchar=SIM900A.read();
        if(inchar=='1')
         {
          delay(10);
          inchar=SIM900A.read();
            if(inchar=='2')
            {
                for (int m=0;m<60;m++)
                {
                  
                    temp[m]=0;
                 }
            }
            
          }
       }
  }
    temp[m]=incoming_char;
     
 } 

 if(temp[50]=='C' && temp[51]=='h' && temp[52]=='e'&& temp[53]=='c'&& temp[54]=='k')  
        {
          SIM900A.println("AT+CMGF=1");                           //Sets the GSM Module in Text Mode
          delay(1000);                                            // Delay of 1000 milli seconds or 1 second
          SIM900A.println("AT+CMGS=\"+60124920726\"\r");          // Mobile number of user
          delay(1000);
          SIM900A.println("Unit: ");                              // Power consumption by user
          SIM900A.println(elapsedkWh);
          SIM900A.println("RM: ");                                // Total cost by user
          SIM900A.println();
          SIM900A.println((char)26);                              // ASCII code of CTRL+Z
          delay(1000);
        }   


   float IBill = 0.00;
   float Irms = emon1.calcIrms(1480);
   float realPower = (Irms*240*4.86*0.85);
   float Bill = (realPower * 21.80 * 1/3600 * 1/1000);
   float TBill = Bill + IBill;
 
if (Irms <= 0.0500)

{
 realPower = 0.00;
 Bill = 0.00;
 TBill = Bill + IBill ;

 }

 else (Irms > 0.0500);

 { realPower = realPower;
 Bill = Bill;
 TBill = Bill + IBill;

 }

 lcd.setCursor(0, 0);
 lcd.print("Power(W):");
 lcd.print(realPower);

 lcd.setCursor(0, 1);
 lcd.print("Price(C):");
 lcd.print(TBill);
 Serial.print(realPower);
 Serial.print(" ");
 Serial.println(TBill);
 delay(500);

  /*
  Output Results - The result of its calculations are to
  be output to the screen (via Serial port).
  */
  Serial.print(" | Power (W): ");
  Serial.print(power, 2);
  Serial.print(" | Energy (kWh): ");
  Serial.print(elapsedkWh, 3);
  Serial.print(" | Pulse Count: ");
  Serial.print(pulseCount);
  Serial.print(" | Millis: ");
  Serial.print(pulseTime);
  Serial.println(" | ");
  delay(3000);


 
}        

// The interrupt routine
void onPulse()
{

//used to measure time between pulses.
lastTime = pulseTime;
pulseTime = micros();

//pulseCounter
pulseCount++;

//Calculate power
power = (3600000000.0 / (pulseTime - lastTime))/ppwh;

//Find kwh elapsed
elapsedkWh = (1.0*pulseCount/(ppwh*1000));                 //multiply by 1000 to convert pulses per wh to kwh

}

declare the variables you use in the interrupt as [url=https://www.arduino.cc/en/Reference/Volatile]volatile[/url]

and don't do the maths into the interrupt function. do that in the main loop. The interrupt code needs to be as short as possible!

in your loop use time management techniques to only display every seconds, or 5 seconds, or when necessary to your LCD

Also this probably does not do what you want.

  if (Irms <= 0.0500)
  {
    realPower = 0.00;
    Bill = 0.00;
    TBill = Bill + IBill ;
  }
[color=red]else (Irms > 0.0500);[/color]

[color=blue]  { realPower = realPower;
    Bill = Bill;
    TBill = Bill + IBill;
  }[/color]

when you listen for data in

 if (SIM900A.available() > 0)
    {
      incoming_char = SIM900A.read();                 //Get the character from the cellular serial port.
      Serial.print(incoming_char);                   //Print the incoming character to the terminal.

      if (inchar == '0')
      {
        delay(10);
        inchar = SIM900A.read();
        if (inchar == '1')
        {
          delay(10);
          inchar = SIM900A.read();
          if (inchar == '2')
          {
            for (int m = 0; m < 60; m++)
            {

              temp[m] = 0;
            }
          }

        }
      }
    }

don't use any Serial.print(incoming_char); nor delay(). Manage communication as it comes.

Thanks for the reply! Do you have any efficient solution to my problem? I can't think any better ways for managing the communication system. I need to send the command to the arduino to get the results and get the feedback from serial monitor.

Have you tried what I suggest above?

  • fix the variables to be volatile
  • remove Serial.print(incoming_char); when you listen for data from the SIM900A (if you need to print, print later when you've got the full command)
  • fix your if (Irms <= 0.0500) {} else {} thingy
  • use time management techniques (and study blink without delay) to display on the LCD only every 5 seconds / when needed only
  • you might want to boost your Serial.begin to 115200 to ensure you don't create unwanted delays and buffer overflows with your computer and debug traces

then try again. it might even work :slight_smile:

I've tried your method, but it seems that it still won't work. Just don't know where the problem is.

Post the full code modified as per suggestion

I didn't know how to use the management technique, try to understand the code but eventually make me more confuse, seem like the input of interrupt disturbing the signal receiving from the GSM, I try stop the loop but it will make the system inefficient.

#include <LiquidCrystal.h>
#include "EmonLib.h"
#include <SoftwareSerial.h>
SoftwareSerial SIM900A(7, 8);
LiquidCrystal lcd(12, 11, 5, 4, 6, 2);
EnergyMonitor emon1; 

int pulse;
long pulseCount = 0;                              //Number of pulses, used to measure energy.
unsigned long pulseTime,lastTime;                 //Used to measure power.
double power, elapsedkWh;                         //power and energy
char inchar;                                      //Will hold the incoming character from the Serial Port.
int led = 8;
int relay = 7;
char incoming_char=0;
char temp[60];
volatile int m=0;
volatile float TBill = 0.0;
volatile float realPower= 0.0;
volatile float IBill = 0.00;
volatile int ppwh = 1;                                     //Number of pulses per wh - found or set on the meter.
                                                  //1000 pulses/kwh = 1 pulse per wh 

 
void setup()
{ 
  SIM900A.begin(115200);
  Serial.begin(115200);                             // Setting the baud rate of Serial Monitor (Arduino)
  delay(10000);                                    // give time to log on to network.
 
  SIM900A.print("AT+CMGF=1\r");                    // set SMS mode to text
  delay(100);
  SIM900A.print("AT+CNMI=2,2,0,0,0\r"); 
  // blurt out contents of new SMS upon receipt to the GSM shield's serial out
  delay(100);
  attachInterrupt(1, onPulse, FALLING);             // KWH interrupt attached to IRQ 1 = pin3
  emon1.current(1, 20);  
  pinMode(pulse, INPUT);
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("Energy Meter    ");
  lcd.setCursor(0,1);
  lcd.print("Interfacing with");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("   Arduino By    ");
  lcd.setCursor(0,1);
  lcd.print("   Ayden Pin   ");
  delay(2000);
}

 
void loop()
{
  
  m=0;
  
  for (int m=0;m<60;m++)
  {
  if(SIM900A.available() >0)
  {
    incoming_char=SIM900A.read();                   //Get the character from the cellular serial port.
    
    
    if(inchar=='0')
      {
        delay(10);
        inchar=SIM900A.read();
        if(inchar=='1')
         {
          delay(10);
          inchar=SIM900A.read();
            if(inchar=='2')
            {
                for (int m=0;m<60;m++)
                {
                  
                    temp[m]=0;
                 }
            }
            
          }
       }
  }
    temp[m]=incoming_char;
     
 } 

 if(temp[50]=='C' && temp[51]=='h' && temp[52]=='e'&& temp[53]=='c'&& temp[54]=='k')  
        {
          SIM900A.println("AT+CMGF=1");                           //Sets the GSM Module in Text Mode
          delay(1000);                                            // Delay of 1000 milli seconds or 1 second
          SIM900A.println("AT+CMGS=\"+60124920726\"\r");          // Mobile number of user
          delay(1000);
          SIM900A.println("Unit: ");                              // Power consumption by user
          SIM900A.println(elapsedkWh);
          SIM900A.println("RM: ");                                // Total cost by user
          SIM900A.println();
          SIM900A.println((char)26);                              // ASCII code of CTRL+Z
          delay(1000);
        }   


   float IBill = 0.00;
   float Irms = emon1.calcIrms(1480);
   float realPower = (Irms*240*4.86*0.85);
   float Bill = (realPower * 21.80 * 1/3600 * 1/1000);
   float TBill = Bill + IBill;
 
if (Irms <= 0.0500)

{
 realPower = 0.00;
 Bill = 0.00;
 TBill = Bill + IBill ;

 }

 lcd.setCursor(0, 0);
 lcd.print("Power(W):");
 lcd.print(realPower);

 lcd.setCursor(0, 1);
 lcd.print("Price(C):");
 lcd.print(TBill);
 Serial.print(realPower);
 Serial.print(" ");
 Serial.println(TBill);
 delay(500);

  /*
  Output Results - The result of its calculations are to
  be output to the screen (via Serial port).
  */
  Serial.print(" | Power (W): ");
  Serial.print(power, 2);
  Serial.print(" | Energy (kWh): ");
  Serial.print(elapsedkWh, 3);
  Serial.print(" | Pulse Count: ");
  Serial.print(pulseCount);
  Serial.print(" | Millis: ");
  Serial.print(pulseTime);
  Serial.println(" | ");
  delay(3000);


 
}        

// The interrupt routine
void onPulse()
{

//used to measure time between pulses.
lastTime = pulseTime;
pulseTime = micros();

//pulseCounter
pulseCount++;

//Calculate power
power = (3600000000.0 / (pulseTime - lastTime))/ppwh;

//Find kwh elapsed
elapsedkWh = (1.0*pulseCount/(ppwh*1000));                 //multiply by 1000 to convert pulses per wh to kwh

}

Anyone have any idea that similar part as me? I need send SMS to check the usage of meter and get back the reading, please help me out.

I see several problems.

Yes, you have to stop the loop. I'm talking about the for(int m... loop. It can't continue counting m when there's no incoming char. Remember serial is very very slow for the Arduino. You can do thousands of different things in between each character arriving, even if serial is sending with no gaps. You've already found that you need to delay(10) between some of the characters. There's probably other useful work you could be doing instead of plugging your ears with a delay.

Change it to a while() loop. Only increment m when it gets a character. Add some timeouts so that it doesn't wait forever. Add some synchronisation so that if it somehow misses the first character of the sequence, it can discard those chars and go back to waiting for the first char.

Where you are looking for the sequence "012" in the incoming data (to inexplicably erase all data) use a state machine rather than just a linear set of reads and delays.