How to print a part of a string to the serial port.

Hello !

I am working on improving an old project of mine where an arduino Mega listens to ascii data coming from a GPS receiver via a hardware serial port and then stores them to a char array.

What i want to do now is use the stored string for printing the Lat and Lon information. The position of theese info in the string are fixed starting from slot 14 to slot 38.

char RcvdChars[] = {"$GPGGA,083729,3758.1553,N,02332.0806,E,0,00,00.0,18.2,M,34.3,M,,*4E"};

for instance in the above code i would like to print all the way from RcvdChars[14] to RcvdChars[38]

how can i do that ?

I thought that maybe with a for statement like this :

void setup()
{
  Serial.begin (9600);
}

void loop ()
{
  char  RcvdChars [] = "$GPGGA,083729,3758.1553,N,02332.0806,E,0,00,00.0,18.2,M,34.3,M,,*4E";
  for (int c=14; c<38; c++)
  {
     Serial.print (RcvdChars[c]);  
  }
}

But i am sure that there is a better and probably faster way of doing so.

THANK YOU.

Here is another way of doing that. This way the number of characters can change and you still get lat, dir, lon, dir. It uses the strtok() function to separate the parts at the commas.

char *strings[20];
char *ptr = NULL;

char  RcvdChars[] = "$GPGGA,083729,3758.1553,N,02332.0806,E,0,00,00.0,18.2,M,34.3,M,,*4E";

void setup()
{
   Serial.begin(115200);

   byte index = 0;
   ptr = strtok(RcvdChars, ",");
   while (ptr != NULL)
   {
      strings[index] = ptr;
      index++;
      ptr = strtok(NULL, ",");
   }
   /* Serial.println(" received  ");
   for (int n = 0; n < index; n++)
   {
      Serial.println(strings[n]);
   }*/
   for(int n = 2; n < 6; n++)
   {
      Serial.println(strings[n]);
   }
}

void loop()
{

}

Output

3758.1553
N
02332.0806
E

Since the data is already in ASCII, you can use Serial.write()

  Serial.write(RcvdChars + 14, 24);

groundFungus:
Here is another way of doing that. This way the number of characters can change and you still get lat, dir, lon, dir. It uses the strtok() function to separate the parts at the commas.

Yes the strtok() is very usefull when delimiters exist and as you pointed out it comes in handy when the length of the array changes.

It does have an issue though. When it "hits" empty fields it skips them. Still not an issue in my particular case.

david_2018:
Since the data is already in ASCII, you can use Serial.write()

  Serial.write(RcvdChars + 14, 24);

That is very interesting and probably the fastest of the above ways. Downside is that will probably make the code a little less "flexible".
Everything in life has its pros and cons right ?

Now i try to figure out the syntax. So i suppose that the +14 is telling the MCU to start printing 14 slots ftom slot 0 right ? but the , 24 ? Does it have to do with the ammount of bytes to be sent ? I dont get it.

Yes now i get it. It is indeed the number of bytes to be sent as explained below.

One last question concerning the Serial.write() function.

I am a little surprised that the +14 that will make the mcu start printing from the 14th slot of the array is not mentioned anywhere in the function's description. Why ?
If it wasnt for you mentioning it, i wouldn't have guessed that.

Downside is that will probably make the code a little less "flexible".

No less flexible than the original for statement. You could use 38-14 instead of 24, as you did in the for statement, and let the compiler do the math for you, or even make the numbers variables for a bit more flexibility.

HellasT:
I am a little surprised that the +14 that will make the mcu start printing from the 14th slot of the array is not mentioned anywhere in the function's description. Why ?

The name of the array, used without brackets, is a char pointer to the memory address where the array is stored in memory. The +14 is adding to the char pointer, giving a char pointer that points to the 14th element of the array. Note that when adding to a pointer, you are actually adding 14 multiplied by sizeof(char), which in this case is actually 14, but if the array were made up of integers, which are 2 bytes each, the compiler would actually add 28.

david_2018:
The name of the array, used without brackets, is a char pointer to the memory address where the array is stored in memory. The +14 is adding to the char pointer, giving a char pointer that points to the 14th element of the array. Note that when adding to a pointer, you are actually adding 14 multiplied by sizeof(char), which in this case is actually 14, but if the array were made up of integers, which are 2 bytes each, the compiler would actually add 28.

I was watching a C lesson about strings yesterday on youtube. I remember the name of the array being a pointer to the 0 element of where it is stored.
It is indeed useful information the comment about multiplication by sizeof which indeed returns the number of bytes for the specific data type.

There is no way i would have known that before. Thank you !

Okay so does anyone know how to print the same information on an I2c LCD ? Is there some function similat to Serial.write () or i just do it with the for statement?

Im going to take a look at the library (LiquidCrystal_I2C.h) functions to see if i can find anything there.

THANK YOU!

A problem that you will run into, writing to the LCD, is that line wrap does not work in the LiquidCrystal libraries. So you will have to keep track of the print position and use the setCursor() function to move the cursor to the next line.

The hd44780 library has line wrap that can be enabled. See the documentation.

Install the hd44780 library. The hd44780 library is the best available for I2C LCDs. The library is available in the Library Manager. Go to Library Manager (in the IDE menus, Sketch, Include Libraries, Manage Libraries) and in the Topics dropdown choose Display and in the Filter your search box enter hd44780. Select and install the hd44780 library by Bill Perry.

The class that you want to use is the hd44780_I2Cexp class. There are examples to show how to use the library. The nice thing about the hd44780 library is that it will autodetect the I2C address and the I2C backpack to LCD pin mapping.

Thank you, i will try your suggestion but i am not sure if i will be able to figure it out since i only know the basics of C and nothing of C++.
For this project line wrap is not a problem since i control the cursor position manually all the time. Actually in most cases i just do character padding.
In the future though i am definetly going to need wrap so it is definetly worth looking into it !

The documentation and examples that come with the library will help you to understand the library. It really is no different from the LiquidCrystal libraries as far as the API is concerned.

The line wrap feature is cool but the automatic sensing of the I2C address and the LCD to I2C backpack are the best features. Plus the library is significantly faster than the others.

And it is not named LiquidCrystal so there is no confusion which library is in use.