Ditching the delay

So we all know how using delays when using serial is out of the options… Nevertheless with gsm modules you can see delays in every example… So i tried to completly remove delays, and I am struggling for a whole day with unsuccess :confused: … I am trying to do that when I make a phone call to my GSM module if the number is correct it should hang up and send message back… The code is working with simple delays, but for practice i decided to go without them… To be honest, I don’t even understand why it won’t work without delays (reading of serial by module should be much faster then arrival of data?) What is happenning is that module won’t send a message (looks like the CTRL+Z (26) isn’t received at all?) If someone is willing to help me understand this I would be greatfull…

#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);

byte SMS = 0;
byte A = 0;

const char number[] = "38598560945";
boolean message = false;
const byte CharNumber = 50; // maximum numbers of bytes
char incomingChar[CharNumber]; // array for incoming message



void receive() { //function for receiving data
  static byte index = 0;
  const char endflag = '\n'; // "n" indicates end of data




  // while reciveing
  while (mySerial.available() > 0 && message == false) // while we receiving
  {

    char in = mySerial.read();
    if (in != endflag) { //if incoming char is not \n keep storing
      incomingChar[index] = in;
      index++;
      if (index >= CharNumber) {
        index = CharNumber - 1;
      } //end if
    } // end if

    else if (in == endflag) {

      message = true;
      incomingChar[index] = '\0'; //terminate
      index = 0;
    }
  }
}

void showNewData() {

  static unsigned long vrijeme; 
  static unsigned long proslovrijeme = 0;


  if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
SMS = 1;
    A = 1;
    mySerial.println("ATH");
  }
  if (A == 1) {

    vrijeme = millis();
    if ((vrijeme - proslovrijeme) >= 500) { // call the function every 500ms instead of delay
      sendSMS();
      proslovrijeme = vrijeme;
    }

  }

  if (message == true) {
    Serial.println(incomingChar);
    message = false;

  }
}

void updateSerial()
{
  
  while (Serial.available())
  {
    mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  receive();
  showNewData();




}

void sendSMS() {

  static byte ST = 0;

  

  if (ST == 0)
  {
   mySerial.println("AT+CMGF=1");
    
    ST = 1;
  }

  if (ST == 1)
  {
mySerial.println("AT+CMGS=\"+38598560945\"");

    
    ST = 2;
  }

  if (ST == 2)
  {
  mySerial.print("AIK"); // sending AIK
 
   ST = 3;
  }
 if (ST == 3){
 mySerial.write(26); //end of text
    ST = 0;
    SMS = 1;
    A = 0;
}


}

void loop() {

  updateSerial();
  mjerenje();



}

byte A = 0;

Does A mean something to you? Doesn't mean a thing to me.

reading of serial by module should be much faster then arrival of data?

Yes, the Arduino can empty the serial buffer faster than it can fill it. It appears as though, in updateSerial(), you think that you have read a complete packet (for some undefined definition of complete packet) from the serial port, because you then send an SMS based on that packet.

But, it is very unlikely that you have a complete packet, in updateSerial().

Yep, the A doesn't mean nothing, i probabbly left it there not intentionally because i am trying the whole day to make this works, and the code was changed many times...

when i wrote like this it works (but i am trying to learn how to avoid delays), but still the packet that you are reffering to is lost after the +CLIP and my number... When i delete ATH command then it is not lost, i get everything printed out on serial monitor... Is that some kind of problem when you try to send data over serial when all the data coming from module still didn't arrived or something like that? Too much for me to figure out by myself obviously, but if you could help me understand :confused:

void sendSMS() {

  mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
  delay(500);
  mySerial.println("AT+CMGS=\"+38598560945\"");//change ZZ with country code and xxxxxxxxxxx with phone number to sms
  delay(500);
  mySerial.print("AIK"); //text content
  delay(500);
  mySerial.write(26);
  delay(5000);
}

if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
    SMS = 1;
    mySerial.println("ATH");
    delay(200);
    sendSMS();
  }

I don't know what is connected to the Serial instance's pins, or what you are sending it, or why.

But, you need to have whatever it is send something that indicates that the stream of bytes has a starting marker and an ending marker. Then, you will know when you have a complete packet from the Serial port, so that you know whether it is time to send an SMS, or not.

As for reading the response from the GPRS device, when you send it AT commands, good luck. The AT command handling process is severely flawed, in my opinion. The device is free to send a response to a command, or not. The device is free to send a carriage return, a line feed, or both, after the response, or not.

Knowing when you have received a complete response to an AT command is problematic.

Here is the example of the blink without delay your code needs.

void sendSMS() {
  static int Counter;
  static int t = 0; // No delay on the first time through
  static unsigned long _ATimer;
  // "static" keeps the value between loops

  // Code here is executed every loop

  if ((millis() - _ATimer) >= (t)) {
    _ATimer = millis();
    Counter++;
    //Code here is executed after t miliseconds are cleared
    switch (Counter) {
      case 1:
        mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
        t = 500;// Set next delay event for 500 ms
        break;
      case 2:
        mySerial.println("AT+CMGS=\"+38598560945\"");//change ZZ with country code and xxxxxxxxxxx with phone number to sms
        t = 500;
        break;
      case 3:
        mySerial.print("AIK"); //text content
        t = 500;
        break;
      case 4:
        mySerial.write(26);
        t = 1000; // Set next delay event for 1000 ms
        Counter = 0;  // Start over
        break;
    }
  }
  // Code here is executed every loop
}

if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
  SMS = 1;
  mySerial.println("ATH");
  delay(200);
  sendSMS();
}

/*
   Blink Without Delay

     Exact Tamer Every timing event is exactly x Seconds no matter what happens in-between this can wind up to have multiple events happen in succession
  static unsigned long _ETimer;
  int t = 1000; // one second
  if ( millis() - _ETimer >= (t)) {
  _ETimer += (t);
  // Your Code Here.
  }
  // Optional:
  while ( millis() - _ETimer >= (t)) _ETimer += (t); // catch up to now if some other delay() wound this up.
  // this windup may be useful but only if you need to repeat this event an exact number of times over a period of time like an alarm clock time. removing the windup would skip these events


     After Timer sometime after this (t) seconds Something could hold it up longer not good for an alarm clock
  static unsigned long _ATimer;
  int t = 1000; // one second
  if ((millis() - _ATimer) >= (t)) {
  _ATimer = millis();
  // Your Code Here.
  }
*/

Z

How I ditch delay()..

Basically I run 2 loop()s.

First loop() runs everything that needs some time and has no delays at all allowed in it. (Looking at buttons, feeding buffers, reading buffers, writing to the screen, checking for updates, running square waves, blinking LEDs.. What have you.

Second loop has a "delay()" but it just takes the time you send in and holds the second loop() while repeatedly calling the first loop() to keep it running.

If I need to wait for something, like a button? I can sit and spin in the second loop() 'till the first loop() sees the button an sets a flag.

Using this, all the delay() issues just kinda' evaporate.

Actually, it really helps to have a timeObj that you can create with a length of time. Then you can just check it in either loop() to see if its time has expired.

-jim lee

zhomeslice:
Here is the example of the blink without delay your code needs.

void sendSMS() {

static int Counter;
static int t = 0; // No delay on the first time through
static unsigned long _ATimer;
// “static” keeps the value between loops

// Code here is executed every loop

if ((millis() - _ATimer) >= (t)) {
_ATimer = millis();
Counter++;
//Code here is executed after t miliseconds are cleared
switch (Counter) {
case 1:
mySerial.println(“AT+CMGF=1”); // Configuring TEXT mode
t = 500;// Set next delay event for 500 ms
break;
case 2:
mySerial.println(“AT+CMGS=”+38598560945"");//change ZZ with country code and xxxxxxxxxxx with phone number to sms
t = 500;
break;
case 3:
mySerial.print(“AIK”); //text content
t = 500;
break;
case 4:
mySerial.write(26);
t = 1000; // Set next delay event for 1000 ms
Counter = 0; // Start over
break;
}
}
// Code here is executed every loop
}

if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
SMS = 1;
mySerial.println(“ATH”);
delay(200);
sendSMS();
}

/*
Blink Without Delay

 Exact Tamer Every timing event is exactly x Seconds no matter what happens in-between this can wind up to have multiple events happen in succession

static unsigned long _ETimer;
int t = 1000; // one second
if ( millis() - _ETimer >= (t)) {
_ETimer += (t);
// Your Code Here.
}
// Optional:
while ( millis() - _ETimer >= (t)) _ETimer += (t); // catch up to now if some other delay() wound this up.
// this windup may be useful but only if you need to repeat this event an exact number of times over a period of time like an alarm clock time. removing the windup would skip these events

 After Timer sometime after this (t) seconds Something could hold it up longer not good for an alarm clock

static unsigned long _ATimer;
int t = 1000; // one second
if ((millis() - _ATimer) >= (t)) {
_ATimer = millis();
// Your Code Here.
}
*/

Z

Hmmm looked fine to me, althought it is very simillar to what I wrote… But when I upload that code, this happens… Looks like trying to use GSM without delays is not so easy, i have a feeling that something else is problem here… My first code was working ok until the Serial.write(26), it seems to me like it doesn’t get received by module or maybe something else… I noticed that when arduino is sending something to GSM module it needs to have some sort of delay after that, because at the same time the module it sending back answers like “RING”, “AT+CLIP” and similar because it is responding to every sent command… And and that excately time problems occur…

the complete code is here with your example, i moved part with strstr in shownewdata() because that is where it belonged (if you think it matters i can move it)… This is interesting to me, i would like to sort this out

#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);



byte SMS = 0;


const char number[] = "38598560945";
boolean message = false;
const byte CharNumber = 50; // maximum numbers of bytes
char incomingChar[CharNumber]; // array for incoming message



void receive() { //function for receiving data
  static byte index = 0;
  const char endflag = '\n'; // "n" indicates end of data




  // while reciveing
  while (mySerial.available() > 0 && message == false) // while we receiving
  {

    char in = mySerial.read();
    if (in != endflag) { //if incoming char is not \n keep storing
      incomingChar[index] = in;
      index++;
      if (index >= CharNumber) {
        index = CharNumber - 1;
      } //end if
    } // end if

    else if (in == endflag) {

      message = true;
      incomingChar[index] = '\0'; //terminate
      index = 0;
    }
  }
}

void sendSMS() {
  static int Counter;
  static int t = 0; // No delay on the first time through
  static unsigned long _ATimer;
  // "static" keeps the value between loops

  // Code here is executed every loop

  if ((millis() - _ATimer) >= (t)) {
    _ATimer = millis();
    Counter++;
    //Code here is executed after t miliseconds are cleared
    switch (Counter) {
      case 1:
        mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
        t = 500;// Set next delay event for 500 ms
        break;
      case 2:
        mySerial.println("AT+CMGS=\"+38598560945\"");//change ZZ with country code and xxxxxxxxxxx with phone number to sms
        t = 500;
        break;
      case 3:
        mySerial.print("AIK"); //text content
        t = 500;
        break;
      case 4:
        mySerial.write(26);
        t = 1000; // Set next delay event for 1000 ms
        Counter = 0;  // Start over
        break;
    }
  }
}

void showNewData() {

  static unsigned long vrijeme; 
  static unsigned long proslovrijeme = 0;


  if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
  SMS = 1;
  mySerial.println("ATH");
  delay(200);
  sendSMS();

  }

  if (message == true) {
    Serial.println(incomingChar);
    message = false;

  }
}






int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout) {

  byte  answer = 0;
  unsigned long previous;

  memset(incomingChar, '\0', 50); // Clean response buffer

  mySerial.println(ATcommand);    // Send the AT command

  previous = millis();

  // this loop waits for the answer
  do {
    receive();
    showNewData();
    // check if the desired answer is in the response of the module
    if (strstr(incomingChar, expected_answer) != NULL) {
      answer = 1;
    }
  }
  // Waits for the answer with time out
  while ((answer == 0) && ((millis() - previous) < timeout));

  return answer;
}

void updateSerial()
{
  //delay(500);
  while (Serial.available())
  {
    mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  receive();
  showNewData();




}






void setup()
{

  

  //Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);

  //Begin serial communication with Arduino and A6
  mySerial.begin(9600);

  Serial.println("Initializing...");
  delay(3000);

  while (sendATcommand("AT", "OK", 1000) == 0) {
    delay(500);
    mySerial.println("AT");
    updateSerial();

  }
  delay(500);
  mySerial.println("AT+CLIP=1"); // show the calling number
  updateSerial();



}



void loop() {

  updateSerial();
  mjerenje();



}

So this works

void showNewData() {

  static unsigned long vrijeme; 
  static unsigned long proslovrijeme = 0;


  if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
    SMS = 1;
    mySerial.println("ATH");
    delay(200);
    sendSMS();
  }
if (message == true) {
    Serial.println(incomingChar);
    message = false;

  }
}


void sendSMS() {

  mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
  delay(500);
  mySerial.println("AT+CMGS=\"+38598560945\"");//configuring phone number
  delay(500);
  mySerial.print("AIK"); //text content
  delay(500);
  mySerial.write(26);
  delay(5000);
}

This almoust works, everything looks ok except for missing the serial.write(26), on the serial monitor everything is ok, but it doesn't send the message

void showNewData() {

  static unsigned long vrijeme; 
  static unsigned long proslovrijeme = 0;


  if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
SMS = 1;
    A = 1;
    mySerial.println("ATH");
  }
  if (A == 1) {

    vrijeme = millis();
    if ((vrijeme - proslovrijeme) >= 500) { // call the function every 500ms instead of delay
      sendSMS();
      proslovrijeme = vrijeme;
    }

  }

  if (message == true) {
    Serial.println(incomingChar);
    message = false;

  }
}

void sendSMS() {

  static byte ST = 0;

  

  if (ST == 0)
  {
   mySerial.println("AT+CMGF=1");
    
    ST = 1;
  }

  if (ST == 1)
  {
mySerial.println("AT+CMGS=\"+38598560945\"");

    
    ST = 2;
  }

  if (ST == 2)
  {
  mySerial.print("AIK"); // sending AIK
 
   ST = 3;
  }
 if (ST == 3){
 mySerial.write(26); //end of text
    ST = 0;
    SMS = 1;
    A = 0;
}


}

So i tried to put a delay (5000) just for testing in ST == 3 after writing down mySerial.write(26), and again it doesn't send a message although i get every single command sent before that on serial monitor... Just don't get it :o

changed this:

void showNewData() {

  static unsigned long vrijeme;
  static unsigned long proslovrijeme = 0;


  if ((strstr(incomingChar, number) != NULL) && (SMS == 0)) {
    SMS = 1;
    mySerial.println("ATH");
// changed and added this line as a flag
    SendingSMS = 1; // *******  Setting this flag ture will allow the loop() to trigger the sendSMS function with Blink Without Delay

  }

  if (message == true) {
    Serial.println(incomingChar);
    message = false;

  }
}
//Added This
int SendingSMS = 0; //as a global
void sendSMS() {
  static int Counter;
  static int t = 200; // 200ms delay on the first time through
  static unsigned long _ATimer;
  // "static" keeps the value between loops

  // Code here is executed every loop
  if (SendingSMS == 0) return; // Added this to exit if not active*****************
  
  if ((millis() - _ATimer) >= (t)) {
    _ATimer = millis();
    Counter++;
    //Code here is executed after t miliseconds are cleared
    switch (Counter) {
      case 1:
        mySerial.println("AT+CMGF=1"); // Configuring TEXT mode
        t = 500;// Set next delay event for 500 ms
        break;
      case 2:
        mySerial.println("AT+CMGS=\"+38598560945\"");//change ZZ with country code and xxxxxxxxxxx with phone number to sms
        t = 500;
        break;
      case 3:
        mySerial.print("AIK"); //text content
        t = 500;
        break;
      case 4:
        mySerial.write(26);
        t = 200; // Set next delay event for 200 ms This is for the next time through 
        Counter = 0;  // Start over
        SendingSMS = 0;  //Added this to stop future loops through after completing **************
        break;
    }
  }
}
void loop() {
  sendSMS(); // Added this line
  updateSerial();
  mjerenje();
}

See if you can see how the additions fit in and how they will set a flag that will allow the loop() function to check the sendSMS function each time through without any delays and once complete we stop looping through the sendSMS() function.

Z