trying to split a char

I am working with a GPS using a software serial port and putting each character into a char array. I need to split all the data such as latitude, longitude, date and time and put them into variables so I can parse the data individually. I am using the strtok() function to separate the comma delimited data. From there I run a loop to separate the tokens and populate the variables. This works great and I get all the data properly. Now I am trying to work with the date variable which is stored as a char but I cant figure out how.The date comes in format HhMmSs (Ex. 062317) and I need to split it into int hours, int minutes, int seconds. Can I split a char like this? If not how can I grab the data differently in order to split it?Here is code for how I am getting the data for the date variable.

char date;
char delimiters[] = ",";
char* valPosition;

void GPRMC(){
  valPosition = strtok(GPRMCC, delimiters);
  i = 0;
  while(valPosition != NULL || i < 11){
    i++;
    valPosition = strtok(NULL, delimiters); 
    if(i==9){
      date = *valPosition;
      Serial.print(F("date = "));
      Serial.println(date);
    }

Here's a tip:

If you are trying to use GPS with arduino, consider using the TinyGPS library. It has a reasonably small footprint and seems relatively easy to use. I am going to use it when I get my GPS hooked up with my autopilot software. Should make things much easier than having to manually parse the data string.

Side note: For some reason, the TinyGPS website is sometimes down... or it might be slow loading.

Zachary

I appreciate that. I have used both tinyGPS library and the sketch from the playground and they both work well. I am trying to write my own in order to learn as well as develop some features for my project that would impossible without a lot of modification to the library.

Hello, an easy solution is to use sscanf

uint8_t h, m, s;
sscanf( date, "%2hhu%2hhu%2hhu", &h, &m, &s );

//or if you really need int..
int h, m, s;
sscanf( date, "%2d%2d%2d", &h, &m, &s );

Another solution..

int
  h = ((date[0] - '0') * 10) + (date[1] - '0'),
  m = ((date[2] - '0') * 10) + (date[3] - '0'),
  s = ((date[4] - '0') * 10) + (date[5] - '0');

I would avoid sscanf(): like printf(), it is one of those first things they teach you not to do in embedded programming 101.

The 2nd approach is what I would use, probably through a macro to structure it a little bit more.

I have tried to split the char as if it were an array but I get an error when I try to compile. For example if I do this it throws as error.

char time;
int hour;

hour = time[0];

I am not sure how to get grab the data other than using a char so I have been stuck using that. Can I convert a char to a char array and then use the suggested method?

I am not sure how to get grab the data other than using a char

It would help if you'd use standard terminology as reflected in the names of the methods/functions you are using. There is no class that has a grab() method, that I know of, and there is no grab() function on the Arduino.

You can only read characters from the serial port. There are methods in the HardwareSerial class that allow you to read more than one character, but, underneath, they read one character at a time. You have to store those characters in an array if you want to deal with more than one of them.

Trying to use array notation on a scalar variable WILL cause the compiler to laugh at you.

PaulS- fair enough, I will try to be more accurate with my terminology. I read each incoming byte on a software serial port and put it into a char array. I split the data using strtok() and use atoi, atol and atof to populate the variables. All of this is working well and I have successfully split all the data based on the comma delimiter and populated all my variables. If all I needed was to print the time variable I would be good. However, I need to do some math with the hours, minutes and seconds and to the best of my knowledge this requires an int. I did not use atol because if the time is 000517 it would populate the time as 517 and drop all the zeros. If it drops the zeros I am not sure what index number represents HhMmSs. Because of this I decided to put the time variable as a char which keeps the zero(s) as a place holder. Now I need to somehow split the char and make int hours, int minutes, int seconds.

valPosition = strtok(GPGGAC, delimiters);
  i = 0;
  while(valPosition != NULL || i < 10){
    i++;  
    valPosition = strtok(NULL, delimiters); //Here we pass in a NULL value, which tells strtok to continue working with the previous string
    if(i==1){
      //time = atol(valPosition); //drops the zeros so I don't know how to split it like this
      time = *valPosition; //saves as a char but I dont know how to split it and change to int 
      Serial.print(F("time = "));
      Serial.println(time);
    }

time = *valPosition; //saves as a char but I dont know how to split it and change to int

valPosition is a pointer. Pointers and arrays are so closely related that you can, for the most part, says that they are the same thing. For your purpose, valPosition and someArray[6] are the same thing.

char hrStg[3], mnStg[3], scStg[3];

hrStg[0] = valPosition[0];
hrStg[1] = valPosition[1];
hrStg[2] = '\0';

mnStg[0] = valPosition[2];
mnStg[1] = valPosition[3];
mnStg[2] = '\0';

seStg[0] = valPosition[4];
seStg[1] = valPosition[5];
seStg[2] = '\0';

int hour = atoi(hrStg);
int min = atoi(mnStg);
int sec = atoi(seStg);

fbriggs4:
I need to do some math with the hours, minutes and seconds and to the best of my knowledge this requires an int.

Guix has already given you some code to convert a string containing hhmmss format into integer hours, minutes and seconds.

PaulS- that worked perfectly, thank you.

PeterH- I did not use the scanf() because I have read here (and elsewhere) that it is not a wise thing to do. I don't know exactly why but I am sure there is good reason why people caution against its use. The second example uses a char array and I didn't have an array so I was not able to make it work.

The second example uses a char array and I didn't have an array so I was not able to make it work.

You do.

guix's code is small and faster.

dhenry- Can you please explain this to me because I really don't get it and I would like to learn. I was storing the variable as char time;, my understanding is that it is not an array. When I tried to treat the variable time like an array I got a compile error.

char time;
int hour;

hour = time[0]; //this gives a compile error for reasons that PaulS described below

The solution that PaulS provided helped me to store the hours, minutes and seconds as char arrays which allows me to split the data and create the int's. Since I was not storing the data as an array I am not clear on how I could make the example by guix work.

Yes sorry mistake in my code, if you replace all "date" by "valPosition" then it should work :slight_smile:

And sscanf is bad only if you need to take care about your memory usage, the first time you use it your code will grow by almost 3 kB, but then you can use it many times, it will NOT grow 3 kB each time you use it. If you use a Arduino Mega then no problem you can use it because it will take only like 1-2 % of the available program memory...

But if you can do something without the need to use sscanf, then do it :wink:

fbriggs4:
I was storing the variable as char time;, my understanding is that it is not an array. When I tried to treat the variable time like an array I got a compile error.

That is correct. Your code was wrong because you were trying to store a 'C' string in a single character. It would have to be a char array in order to hold a string, and once the variable is declared correctly you can manipulate the string held in it using any of the techniques that guix and PaulS showed you.

thanks everyone, that makes sense now.