Program only works if I press hardware reset button or open Serial Monitor.

Hi,
I am quite new to Arduino world.

I am using Arduino UNO and SIM900A module(image from instructables site).

So, my goal is this.
I check for recognized incoming numbers.
When the ring count reaches to 3, I hangup the call and turn the LED.

So, I wrote the code. I upload the code and it works.
I leave the device powered off for a while(some times 1 min, sometimes 5), and power the devices on, and when I give the ring, it just goes on and on.
It could be problem with SoftwareSerial, then I also used NeoSWSerial in place of it, still doesn't work(after powering off for a while). And, if I press reset button on the board, I give ring, it counts to 3 and hangs up the call. I don't know what's causing this.

It works 100% of time with Serial Monitor open.
I also used EEPROM to save last LED status.
Another issue is, the portion when I read last LED status, it works, even if the RING portion doesn't.


My code is:

#include <NeoSWSerial.h>
#include <EEPROM.h>
NeoSWSerial sim(3, 2); //T, R
const byte numChars = 40;
char receivedChars[numChars];
char number[10];
char numbers[2][10] = {
  "1234567890", //number1
  "2345678901" //number2
};
bool known = false; // is the number known
byte count = 0;
unsigned long time1, time2 = 0;
bool time1Set = false;
byte isTurnedOff;
byte MEMORY = 25;
byte LED = 5;
void setup()
{

  sim.begin(9600);   // Setting the baud rate of sim Module
  sim.setTimeout(2000);
  pinMode(LED, OUTPUT);
  sim.write("AT+CLIP=1\r"); // enable incoming call details
  delay(1000);
}

void loop() {

  if (millis() == 2000) { // check last status after 2 seconds of powering on.
    isTurnedOff = EEPROM.read(MEMORY);
    if (isTurnedOff == 1) {
      //    turn the LED off
      turnLEDOff();
    }
    else if (isTurnedOff == 0) {
      //    turn it on
      turnLEDOn();
    }
  }
  recvWithStartEndMarkers();
  if (count == 3) {
    if (isTurnedOff == 1) {
      turnLEDOn();
    }
    else {
      turnLEDOff();
    }
    hangupCall();
  }
  time2 = millis();
  if (time1Set && (unsigned long)(time2 - time1) > 6000 && (count != 3)) {
    time1Set = false;
    count = 0; // reset the count to 0 if I don't get 3 rings in 6 seconds.
  }
}


void recvWithStartEndMarkers() {

  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '+';
  char endMarker = ',';
  char rc;
  int i = 0;
  int j = 11;

  while (sim.available() > 0) { //
    
    delay(10);
    rc = sim.read(); // Serial.read() means what we enter in Serial Monitor and sim.read() means what we get from the module
    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        if ((strncmp(receivedChars, "CLIP", 4) == 0)) {
          for (i = 0; i < 10; i++) {
            number[i] = receivedChars[j++];
          }
        }
        if (checkNumber()) {
          time1 = millis();
          time1Set = true;
          count += 1;
          
        } else {
          hangupCall();
        }
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
      digitalWrite(LED, HIGH);
    }

  }
}
bool checkNumber() {
  int i = 0;
  int num = sizeof(numbers) / sizeof(numbers[0]);
  for (; i < num; i++) {
    if (strncmp(number, numbers[i], 10) == 0) {
      return true; // number known
    }
  }
  return false;
}
void hangupCall() {
  sim.write("ATH\r\n"); // using write here
  delay(100);
  count = 0;
}

void turnLEDOff() {
  digitalWrite(RELAY, LOW);
  isTurnedOff = 1;
  EEPROM.write(MEMORY, isTurnedOff);
  // Serial.println("LED off");
  delay(50);
}

void turnLEDOn() {
  digitalWrite(RELAY, HIGH);
  isTurnedOff = 0;
  EEPROM.write(MEMORY, isTurnedOff);
  // Serial.println("LED on");
  delay(50);
}
char numbers[2][10] =
{
  "1234567890", //number1
  "2345678901" //number2
};

The array needs to declared [2][11] to allow for the '\0' that is added to terminate the string. As it is you are writing over memory that is not allocated to the array

Hi,
The logic of my program is this:

  1. Check if there is an incoming call.
    1.1 If there is incoming call, check if it is from known list of numbers.
    1.1.1 If the number is known, count the RINGs upto 3 and hangup and turn on/off the LED depending on last status(toggle).
    1.1.2 If the number is unknown hangup the call.

I upload the program to UNO, and it works nicely. Hangs up known calls after 3 rings and toggles LED.
And, after disconnecting power for a while, I reconnect the device to power. And, call the module(from known number), it doesn't disconnect the call after 3 rings. And, at that condition if I press reset button, then same program works, toggles and everything. Or, opening Serial Monitor have the same effect, program working.

I am supplying 12V 1A to UNO and 5V 2A to module.


My code:

#include <NeoSWSerial.h>
#include <EEPROM.h>
NeoSWSerial sim(3, 2); //T, R
const byte numChars = 40;
char receivedChars[numChars];
char number[10];
char numbers[2][10] = {
  "1234567890", // number1
  "1234567894" // number2
};
bool known = false; // is the number known
byte count = 0; // ring count
unsigned long time1, time2 = 0;
bool time1Set = false;
byte isTurnedOff;
byte MEMORY = 25; // to save last LED status to eeprom
byte LED = 5;
void setup()
{

  sim.begin(9600);   // Setting the baud rate of sim Module
  sim.setTimeout(2000);
  pinMode(LED, OUTPUT);
  sim.write("AT+CLIP=1\r");
  delay(1000);
}

void loop() {

  if (millis() == 2000) {
    isTurnedOff = EEPROM.read(MEMORY); // last status of LED
    if (isTurnedOff == 1) {
      //    turn the LED off
      turnLEDOff();
    }
    else if (isTurnedOff == 0) {
      //    turn it on
      turnLEDOn();
    }
  }
  recvWithStartEndMarkers();
  if (count == 3) { // if count is 3 hangup and toggle led
    if (isTurnedOff == 1) {
      turnLEDOn();
    }
    else {
      turnLEDOff();
    }
  }
  time2 = millis(); 
  if (time1Set && (unsigned long)(time2 - time1) > 6000 && (count != 3)) { // if count doesn't reach 3 
    time1Set = false;                                                                         // in 6 seconds, it's missed
    count = 0;
  }
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '+';
  char endMarker = ',';
  char rc;
  int i = 0;
  int j = 11;

  while (sim.available() > 0) { // here instead of Serial use sim  && newData == false
    
    delay(10);
    rc = sim.read(); // Serial.read() means what we enter in Serial Monitor and sim.read() means what we get from the module
    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        if ((strncmp(receivedChars, "CLIP", 4) == 0)) {
          for (i = 0; i < 10; i++) {
            number[i] = receivedChars[j++]; // get the phone number
          }
        }
        if (checkNumber()) { // if known number
          time1 = millis();
          time1Set = true;
          count += 1;
          
        } else {
          hangupCall();
        }
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;    
    }
  }
}
bool checkNumber() {
  int i = 0;
  int num = sizeof(numbers) / sizeof(numbers[0]);
  for (; i < num; i++) {
    if (strncmp(number, numbers[i], 10) == 0) {
      return true;
    }
  }
  return false;
}
void hangupCall() {
  count = 0;
  sim.write("ATH\r\n");
  delay(100);
  
}

void turnLEDOff() {
  digitalWrite(LED, LOW);
  isTurnedOff = 1;
  EEPROM.write(MEMORY, isTurnedOff);
  delay(50);
}

void turnLEDOn() {
  digitalWrite(LED, HIGH);
  isTurnedOff = 0;
  EEPROM.write(MEMORY, isTurnedOff);
  delay(50);
}

I don't even know what is issue is here.
Any help would be appreciated.

Wow, good catch. Thanks.
But, it didn't solve the problem.

It could be related to the timing of the initialization of the GSM modem. When you power everything on, the Uno and the GSM modem are starting at the same time, so perhaps the GSM modem is not ready by the time you the Uno sends the initialization command. When you reset the Uno, the GSM modem is not also reset, so it is already running when the Uno starts the sketch. When you open Serial Monitor, the Uno is reset, so this has the same effect as you pressing the reset button on the Uno.

Hi Pert, thanks for clarifying.
So, I should delay the setup more like 10 seconds or something.
Let me get back after trying this.

It's worth a try. Let us know what happens.