Serial Monitor Not Printing What it Should - Nano

Hi,

Would like someone's opinion on why the serial monitor is not printing out everything that it should be printing. Let me explain.

I have an Arduino Nano connected to a SIM7000E 4G module that has GPS capabilities.

I have written simple code to turn on GPS and grab GPS coordinates:

#include <SoftwareSerial.h>

SoftwareSerial SIM7000E(10, 11); //RX, TX

int rx=10;
int tx=11;

void setup() {
  // put your setup code here, to run once:

pinMode(tx,OUTPUT);
pinMode(rx,INPUT);

Serial.begin(9600);
delay(1000);

SIM7000E.begin(19200);
delay(1000);

Serial.println("Initialising");
delay(1000);

SIM7000E.print("AT+CGNSPWR=1\r\n");
while(SIM7000E.available())
Serial.write(SIM7000E.read());
delay(5000);

SIM7000E.print("AT+CGNSINF\r\n");
while(SIM7000E.available()) 
Serial.write(SIM7000E.read());
delay(5000);

SIM7000E.print("AT\r\n");
while(SIM7000E.available())
Serial.write(SIM7000E.read());
delay(2000);


}

void loop() {
  // put your main code here, to run repeatedly:

}

This is the output in the serial monitor:

Initialising

AT+CGNSPWR=1

OK

AT+CGNSINF

+CGNSINF: 1,1,20221021110122.000,-29.521587,163.05

The serial monitor prints the time and some of the coordinates. But nothing else.

It should be printing this:

AT+CGNSINF

+CGNSINF: 1,1,20221021111301.000,-29.521587,163.054521,20.000,0.00,30.3,1,,1.6,1.8,0.9,,16,6,1,,,39,,

OK

Does anyone know why the serial monitor doesn't print anything after "163.05"?

Thank youu

yep Your receive buffer filled to overflow while you were twiddling your thumbs with delays

1 Like

You're right. When I change the delays I get different outputs. I am trying to work on it now.

#include <SoftwareSerial.h>

SoftwareSerial SIM7000E(10, 11); //RX, TX

int rx=10;
int tx=11;

void setup() {
  // put your setup code here, to run once:

pinMode(tx,OUTPUT);
pinMode(rx,INPUT);

Serial.begin(9600);
delay(1000);

SIM7000E.begin(19200);
delay(1000);

Serial.println("Initialising");
delay(1000);

char data [16]; 

SIM7000E.print("AT+CGNSPWR=1\r\n");
if (SIM7000E.available() >= 16){
  for (int i=0; i<16; i++) {
  data[i] = SIM7000E.read();
  }
}

Serial.print(data); 

}

void loop() {
  // put your main code here, to run repeatedly:

}

Trying to do something like this but nothing is really happening. I just get "Initialising" and then a square box.

I have a feeling the different baud rates are why i am having trouble

By the time your code gets to the if statement, there will more than likely not be 16 characters received. So you will never read the GPS.

SIM7000E.print("AT+CGNSPWR=1\r\n");
while(1)
{
  if (SIM7000E.available())
  {
    char c = Serial.read();
    if (c < 0x10)
    {
      Serial.print("0");
    }
    Serial.print(c, HEX);
    Serial.print(" ");
  }
}

You will get an output like

2B 43 47 ...

Those are the HEX representations of the data that you have received. You can look them up on e.g. https://www.asciitable.com/. The last one or two are the important ones for you to continue. They are probably 0A and 0D or a combination of that; 0A is a line feed and 0D is a carriage return.

Once you know that, you can read your SIM data into an array; you need to make sure that your array is big enough to hold the full message plus a terminating '\0'; looking at the output of your opening post, 16 will not be enough !

E.g. to read up to the 0A

char data[128];
SIM7000E.print("AT+CGNSPWR=1\r\n");
SIM7000E.readBytesUntil('\n', data, sizeof(data));

E.g. to read up to the 0D

char data[128];
SIM7000E.print("AT+CGNSPWR=1\r\n");
SIM7000E.readBytesUntil('\r', data, sizeof(data));

Those are not perfect but should get you started. Problem with readBytesUntil is that it's blocking for a short while. If that poses a problem, you can read Serial Input Basics - updated to get ideas for non-blocking receive code and you will need a simple mechanism to only send again once you have received the full message.

1 Like

+1 for Serial Input Basics - updated.

1 Like

The main problem is your code is much faster than the speed that data comes in over serial. So the serial buffer empties, and your code keeps going thinking it has received a full reply when it hasn't.

Try this ...

void getReply()
(
  unsigned long start = millis();
  boolean waitingForReply = true;

  while (millis() - start < 50 || waitingForReply)
  {
    if (SIM7000E.available() > 0)
    {
      waitingForReply = false;
      start = millis();
      Serial.write(SIM7000E.read());     
    }
  }
}

This will wait 50ms (adjust as required for different baud rates) after the last character has been received before continuing.

Then call getReply() after you send each command...

1 Like

Hey thanks for the suggestion of using readBytesUntil.

However, instead of "SIM7000E.readBytesUntil('\n', data, sizeof(data)),

I used "SIM7000E.readBytesUntil('K', data, sizeof(data))

Because the results for the first ended too early and the coordinates did not show. But the second one works because the results end in "OK". That might not be how it works but at least all the coordinates show.

I was also able to isolate just the coordinates with the following code:

SoftwareSerial SIM7000E(10, 11); //RX, TX

int rx=10;
int tx=11;

void setup() {
  // put your setup code here, to run once:

pinMode(tx,OUTPUT);
pinMode(rx,INPUT);

Serial.begin(9600);
delay(1000);

SIM7000E.begin(19200);
delay(1000);

Serial.println("Initialising");
delay(1000);

char data[128];
SIM7000E.print("AT+CGNSINF\r\n");
SIM7000E.readBytesUntil('K', data, sizeof(data));
char *data1 = strtok(data, ",");
char *data2 = strtok(NULL, ",");
char *data3 = strtok(NULL, ",");
char *data4 = strtok(NULL, ",");

Serial.print(data4);
char *data5 = strtok(NULL, ",");
Serial.print(data5);

}
void loop() {
  // put your main code here, to run repeatedly:

}

Hey thanks for the suggestion. It looks like sterretje's suggestion works fine for now though.

That's usually not good enough :wink: If the OK had a 0D and/or 0A following it, that will stay on the buffer and might affect the next reading.

The same will happeen if your SIM7000 appends one or both of those characters; reading to e.g. '\n' will leave the OK in the buffer and the next time you will just get that.

Therefore you need to understand what you get back; that could be (I don't know) one line with the GPS information (and some termination) followed by one line with the OK (and some termination).

If you know that you get two lines, read and process one firstand next read (and process if needed) the second line.

Just my thoughts.

Note:
If your topic is solved, please click the solution button under the most useful post to let others know that it is solved.

That's usually not good enough :wink:

Yeah you're right I have already ran into problems now that I am trying to make everything loop every 30 seconds.

I will try as you say and read and process one line and then read and process the next. I thought I was already doin that with the "strtok".

Although I think that my issue now is that I need the serial input buffer to be empty before the commands start over again.

strtok() does not know about lines. You can use it to split a null-terminated character array on line-endings ('\r' or '\n').

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