SMS not working when replace delay with millis

#include <SoftwareSerial.h>
SoftwareSerial mySerial(9, 10);
char msg;
char call;

unsigned long startsms = 0;

unsigned long messageperiodsms1 = 1000;
unsigned long previousMillissms1 = 0;

unsigned long messageperiodsms2 = 2000;
unsigned long previousMillissms2 = 0;

unsigned long messageperiodsms3 = 2100;
unsigned long previousMillissms3 = 0;

unsigned long messageperiodsms4 = 3100;
unsigned long previousMillissms4 = 0;

void setup()
{
  mySerial.begin(9600);   // Setting the baud rate of GSM Module  
  Serial.begin(9600);    // Setting the baud rate of Serial Monitor (Arduino)
  Serial.println("GSM SIM900A BEGIN");
  Serial.println("Enter character for control option:");
  Serial.println("h : to disconnect a call");
  Serial.println("i : to receive a call");
  Serial.println("s : to send message");
  Serial.println("c : to make a call");  
  Serial.println("e : to redial");
  Serial.println();
  delay(100);
}

void loop()
{  
  if (Serial.available()>0)
   switch(Serial.read())
  {
    case 's':
      SendMessage();
      break;
    case 'c':
      MakeCall();
      break;
    case 'h':
      HangupCall();
      break;
    case 'e':
      RedialCall();
      break;
    case 'i':
      ReceiveCall();
      break;
  }
 if (mySerial.available()>0)
 Serial.write(mySerial.read());
}

void SendMessage() {
  mySerial.println("AT+CMGF=1"); 
  //delay(1000);
  startsms = millis();
  if(startsms - previousMillissms1 > messageperiodsms1){
  previousMillissms1 = startsms;
  mySerial.println("AT+CMGS=\"+6xxxxxxxxxx\"\r");
  //delay(1000);
  }
  if(startsms - previousMillissms2 > messageperiodsms2){
  previousMillissms2 = startsms;
  mySerial.println("MESSAGE HERE");
  //delay(100);
  }
  if(startsms - previousMillissms3 > messageperiodsms3){
  previousMillissms3 = startsms;
  mySerial.println((char)26);
  //delay(1000);
  }
  if(startsms - previousMillissms4 > messageperiodsms4){
  previousMillissms4 = startsms;
  }
}

void ReceiveMessage()
{
  mySerial.println("AT+CNMI=2,2,0,0,0"); // AT Command to recieve a live SMS
  delay(1000);
  if (mySerial.available()>0)
  {
    msg=mySerial.read();
    Serial.print(msg);
  }
}

void MakeCall()
{
  mySerial.println("ATD+6xxxxxxxxxx;"); // ATDxxxxxxxxxx; -- watch out here for semicolon at the end!!
  Serial.println("Calling  "); // print response over serial port
  delay(1000);
}


void HangupCall()
{
  mySerial.println("ATH");
  Serial.println("Hangup Call");
  delay(1000);
}

void ReceiveCall()
{
  mySerial.println("ATA");
  delay(1000);
  {
    call=mySerial.read();
    Serial.print(call);
  }
}

void RedialCall()
{
  mySerial.println("ATDL");
  Serial.println("Redialing");
  delay(1000);
}

Hello, above code is for GSM module. It working fine but I wonder if I can replace the delay() with millis() at the SendMessage(). The delay() causes blocking on my code. Still works fine with delay() but not working when I try to use millis(). Is this possible or am I just wasting effort trying to replace the delay() with millis?

You don't need all the delays... probably only one after the

AT+CMGS=\"+6xxxxxxxxxx\"\r"

command... this is to allow the modem to respond with a prompt, so you can then send the message... probably only 100ms or so will do.

These commands only need to be issued once, so you can put them in your setup

"AT+CMGF=1"

"AT+CNMI=2,2,0,0,0"

It’s not as easy as it looks, because there are three phases required to send a message.
Plus there are other AT functions that can make life a lot easier in a real-time system.

The only way to do it is with a state-machine that tracks the message sending phase progress.

I’ve been considering developing a generic class to do this, but health has slowed me down.
I have the code working (based on the FONA library, but it’s quite tangled at the moment.

As an example - the code simultaneously handles about 30 concurrent millis() timing counters, along with flashing LEDs, timing relays, serial messages, text command parsing and other functions.

Thanks, it does work although the lowest I can replace the delay with a value of 130ms. Hopefully, my sensor will work this time. My sensor refreshes value every second, whenever I try to incorporate the sendmessage my sensor reading is not as accurate as before, I suspect due to the delay().

Plus there are other AT functions that can make life a lot easier in a real-time system.

May I know which one or what it is called. Thank you in advance!

Where in your code are you getting the sensor value?

You will need code to handle the reponses you get from the modem. These will be a mixture of command replies, plus unsolicited result codes (URC) messages. URCs happen for example when a call or SMS come in.

I didn't include it in the code for the sensor. The previous code I posted is just me checking if it is possible to replace the delay() with millis(). But your solution given does partially solves my problem. Although I prefer if I can just totally get rid of the delay.

You should be able to get rid of most of the delay statements altogether. The only one I think you need is after the AT+CMGS=\"+6xxxxxxxxxx\"\r" command is sent.

If your sensor only refreshes every second then this small delay should make no difference.

... and the reason your code didn't work when you replaced the delays with millis() is because you are only checking the times once... the code needs to be in a loop.

This seems to work! Also I just put only 1 millis after AT+CMGS="+6xxxxxxxxxx"\r" replacing delay instead of putting multiple in between mySerial.println

All the AT commands available for your particular modem will be in the reference material for the modem. About 90% of the commands are standardised across miss modem chipsets.

You only need to use those particular functions that your program needs.

BTW, another technique which I use, is a message queue, which allows me to push as many messages into the queue - as fast as the memory will allow, then the modem operates independently to actually send those messages with retries etc.

This non blocking method allows all those millis() timers to run while the modem sends the backlog of queued messages without slowing anything down.