SIM800L Receiving longer SMS

Hello.

I am trying to get a SIM800L reliably recalling SMS from the SIM800L using the "AT+CMGR=X" command. I understand that "AT+CNMI=X,X" can be used to change how the SMS is stored, but I want to use AT+CMGR=X to choose when I read the SMS, so I don't have to immediately capture it when it comes in.

To be clear:

  • I have the power to the SIM800L working fine (I have the v2 board, and replaced the not in spec capacitor on the board) - most issues with the SIM800L can be related to this power issue but I believe I have that sorted.
  • I can receive short SMS perfectly fine.
  • I can send SMS perfectly fine.

I have looked over the internet a lot and ALL the use cases I can find where the SIM800L is used, only have short 1-10 strings of SMS being recalled from the SIM800L.

I am trying to reliably recall the SMS from the SIM800L no matter what length of SMS is ready to be recalled. I understand that this max length is 160, and 153 when it is a concatenated SMS over multiple index.

I am just really stuck trying to get a consistent recall of the SMS back from the SIM800L and storing it into a usable string or char array for use in a code which does not have a serial monitor such as an LCD.

To be clear, when using the serial available, serial write (like basic examples of the SIM800L use), everything works fine, every time. When writing directly to the serial monitor from the SIM800L, it works every time. I am just having issues getting the serial data, consistently into a string or char array for printing out on say a LCD. Hence I think it is an issue with my code, or how I am using SoftwareSerial and the SIM800L.read();.

if (Serial.available()) 
{
    SIM800L.write(Serial.read());
 }

I have tried to take each byte from the serial read from the SIM800L and store it. But I find that runs into issues when the SMS is longer (it just does not read the SMS after 54 characters).

I have tried other methods of reading and storing from the SIM800L. And currently I have tried to implement a, if data is available wait a bit of time to capture that data. I thought this was working well, but for longer messages I still run into a problem. This code, which contains my other commented out methods also, is shown below.

With this if data is available wait a bit of time to capture that data code, for longer SMS only, every other recall of the message has erroneous recall of the SMS, and I cannot understand why.

Please see the serial output below which shows this. I have tried another serial monitor, and I have set both the SIM800L and the serial monitor at 9600baud which has caught others out when searching online.

For the SMS, I have used a string of a's, each capital A represents a set of 10 a's (including the A), so a max 160 length message test.

Serial monitor data

09:17:17.898 -> Data: AT+CMGR=3,1
09:17:17.898 -> OK
09:17:17.898 -> 
09:17:17.898 -> +CMGR: "REC READ","+44XXXXXXXXXX","","25/05/02,17:17:32+04"
09:17:17.932 -> AaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaa
09:17:18.098 -> 
09:17:18.098 -> OK
09:17:18.098 -> 
09:17:20.898 -> Data: AT+CMGR=3,1
09:17:20.898 -> +CMGR: "REC READ","+44XXXXXXXXXX","","25/05/02,17aaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaa
09:17:20.966 -> 
09:17:21.008 -> OK
09:17:21.008 -> 
09:17:23.892 -> Data: AT+CMGR=3,1
09:17:23.892 -> +CMGR: "REC READ","+44XXXXXXXXXX","","25/05/02,17:17:32+04"
09:17:23.934 -> AaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaa
09:17:24.108 -> 
09:17:24.108 -> OK
09:17:24.108 -> 
09:17:26.870 -> Data: AT+CMGR=3,1
09:17:26.870 -> +CMGR: "REC READ","+44XXXXXXXXXX","","25/05/02,17aaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaa
09:17:27.015 -> 
09:17:27.015 -> OK
09:17:27.015 -> 

Code:

#include <SoftwareSerial.h>

SoftwareSerial SIM800L(6, 7); // RX | TX

const unsigned int MAX_SIM800Ldata_LENGTH = 160; 
String SIM800LdataBuf = "";
char bufChar;
char SIM800Ldata[MAX_SIM800Ldata_LENGTH];
boolean newData = false;

static unsigned long setTime = 0;
static unsigned long goTime = 0;
static const unsigned long recievePeriod = 1000; // ms
static unsigned long timeNow = 0;
boolean timerOn = true;
static const unsigned long testTime = 3000; // ms

void setup() {
  
  setTime = millis();

  // Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);
  
  // Begin serial communication with SIM800L
  SIM800L.begin(9600);
  SIM800L.println("AT");
  delay(100);
  
  // Set SMS Message Format
  SIM800L.println("AT+CMGF=1");
  getData();
  printData();

  //Show some optional elements of responses (such as <length> in SMS read).
  SIM800L.println("AT+CSDH=0");
  getData();
  printData();
}

void loop() 
{
  timeNow = millis();

 //**********************
 //This section of code is just to emulate the AT+CMGR= command 
 //being used to get the SMS from the SIM800L, as the end goal will be to 
 //display incoming SMS on an LCD at specified times (simplified to get the 
 //basics working fist - what I am having issues with).
  if(timeNow - goTime > testTime)
	{
		goTime = millis();
    
    SIM800L.println("AT+CMGR=3,1");
	}
//**********************

  //if (Serial.available()) {
  //  SIM800L.write(Serial.read());
  //}

  getData();
  printData();
}

void getData()
{
  /*
  while (SIM800L.available())
  {
    bufChar = SIM800L.read();
    SIM800LdataBuf.concat(bufChar);
    //strcat (SIM800LdataBuf, bufChar);
    
    if (bufChar == '\r')    // line feed 0x0A 'n', carriage return 0x0D '\r'
    {
      newData = true;
    }
  }
  */

  if (SIM800L.available())
  {
    if (timerOn != true)
    {
      timerOn = true;
      setTime = millis();
    }
    
    if (timeNow - setTime <= recievePeriod)
    {
      while (SIM800L.available())
      {
      bufChar = SIM800L.read();
      SIM800LdataBuf.concat(bufChar);
      }
    }
    else
    {
      timerOn = false;
      newData = true;
    }
  }

  /*
  // If there's any serial available from SIM800L, read it and send it out
  // through Arduino's UART (Serial Monitor)
  if (SIM800L.available()>0)
  { 
    static unsigned int SIM800Ldata_pos = 0;      //because these are static they only get set once.
    
    while (SIM800L.available()>0) 
    {
      char incomingByte = SIM800L.read();

      if ((incomingByte != '\n') && (SIM800Ldata_pos < MAX_SIM800Ldata_LENGTH - 1))     // line feed 0x0A 'n', carriage return 0x0D '\r'
      {
        SIM800LdataBuf[SIM800Ldata_pos] = incomingByte;
        SIM800Ldata_pos++;
      }
      else
      {
        SIM800LdataBuf[SIM800Ldata_pos] = '\0';    //terminate string
        //Serial.print("Pos: ");
        Serial.println(SIM800Ldata_pos);
        strcpy(SIM800Ldata,SIM800LdataBuf);
        SIM800Ldata_pos = 0;
        newData = true;
      }
    }
  }
  */
}

void printData()
{
  if (newData == true) 
  {
    Serial.print("Data: ");
    Serial.println(SIM800LdataBuf);
    SIM800LdataBuf = "";
    //memset(SIM800LdataBuf,'\0',sizeof(SIM800LdataBuf));
    newData = false;
  }
}

Additional piece of info...

If the section of code used to emulate the AT+CMGR= command is removed, and the serial monitor is used to enter the command as per below, the first response (from my code at least) is just "Data:" with none of the AT+CMGR= response (see below ref 1).

If I press enter on the serial monitor without typing anything else in, the AT+CMGR= response is seen (see below ref 2). I think there is something I am missing with this. Not necessarily that will fix the issue above, but another issue at least.

Serial monitor code to input AT commands manually

if (Serial.available()) {
    SIM800L.write(Serial.read());
  }

Other Issue ref 1

18:44:58.827 -> Data: AT
18:44:58.827 -> OK
18:44:58.827 -> AT+CMGF=1
18:44:58.827 -> OK
18:44:58.827 -> AT+CSDH=0
18:44:58.860 -> OK
18:44:58.860 -> 
18:45:22.904 -> Data: 

Other Issue ref 2

18:44:58.827 -> Data: AT
18:44:58.827 -> OK
18:44:58.827 -> AT+CMGF=1
18:44:58.827 -> OK
18:44:58.827 -> AT+CSDH=0
18:44:58.860 -> OK
18:44:58.860 -> 
18:45:22.904 -> Data: 
18:47:56.701 -> Data: AT+CMGR=1,1
18:47:56.701 -> +CMGR: "REC READ","+44XXXXXXXXXX","","25/05/01,18:20:40+04"
18:47:56.734 -> AaaaaaaaaaAaaaaaaaaaAaaaaaaaaaAaaaaaaaaa
18:47:56.768 -> 
18:47:56.768 -> OK
18:47:56.803 -> 

I fixed my issue. Like I guessed... problems with my code... Basically I was not ensuring the timings were set up correctly. The main issue was changing the timing comparison from an if to a while as shown below.

while (timeNow - setTime <= recievePeriod)

The additional info I posted above, and using the serial monitor throughout each logical statement, testing each variable, also really helped get down to what I was doing wrong.

I'm not 100% sure if I am allowed to link to another forum so I wont as I do not want to break any rules, but if you google the following sentence you will arrive at the forum post that also helped me get over the line with this:

"How to read GSM AT command response on arduino Serial port for long response?"

Working code

void loop() 
{
  timeNow = millis();
  
  //**********************
  //This section of code is just to emulate the AT+CMGR= command 
  //being used to get the SMS from the SIM800L, as the end goal will be to 
  //display incoming SMS on an LCD at specified times (simplified to get the 
  //basics working fist - what I am having issues with).
  if(timeNow - goTime > testTime)
	{
		goTime = millis();
    SIM800L.println("AT+CMGR=3,1");
	}
  //**********************
  
  //if (Serial.available()) {
  //  SIM800L.write(Serial.read());
  //}
  
  getData();
}

void printData()
{
    Serial.print("Data: ");
    Serial.println(SIM800LdataBuf);
    SIM800LdataBuf = "";
    //memset(SIM800LdataBuf,'\0',sizeof(SIM800LdataBuf));
}

void getData()
{
  if (SIM800L.available())
  {
    
    if (timerOn != true)
    {
      timerOn = true;
      timeNow = millis();
      setTime = millis();
    }
    
    while (timeNow - setTime <= recievePeriod)
    {
      if (SIM800L.available())
      {
        bufChar = SIM800L.read();
        if (bufChar != -1)
        {
          SIM800LdataBuf.concat(bufChar);
          timeNow = millis();
          setTime = millis();
        }
      }
      else
      {
        timeNow = millis();
      }
    }
    timerOn = false;
    printData();
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.