Decode comma separated values

Hello i am trying to decode data that is coming from excel and i need a bit of help,

here is what a string might look like that is coming over the serial port

12.3,23,45.6,345,67.......... 16 numbers in total (15 commas). All floats

here is some example code that @Robin2 made that i am trying to get working but in that code he has <> for start and end data steams so that is screwing me up. if someone could modify that code a bit would be greatly appreciated!

// Example 5 - Receive with start- and end-markers combined with parsing

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integerFromPC = 0;
float floatFromPC = 0.0;

boolean newData = false;

//============

void setup() {
    Serial.begin(9600);
    Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");
    Serial.println("Enter data in this style <HelloWorld, 12, 24.7>  ");
    Serial.println();
}

//============

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
    }
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integerFromPC = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");
    floatFromPC = atof(strtokIndx);     // convert this part to a float

}

//============

void showParsedData() {
    Serial.print("Message ");
    Serial.println(messageFromPC);
    Serial.print("Integer ");
    Serial.println(integerFromPC);
    Serial.print("Float ");
    Serial.println(floatFromPC);
}

Hello my friend
You can follow this link, you will find everything that will help you regarding the Excel data
It is better to proceed with understanding than to take a code that you know nothing about, even if something goes wrong you can solve it

strtok is normally used for this.

A simple example:


/* strtok() Arduino example for a string contained in 
   the source code.  

   based on the reference example at: 
   http://www.cplusplus.com/reference/cstring/strtok/

   Zac Staples. July, 2013.
*/

void setup() {
  Serial.begin(115200);
  char str[] = "{label,4,8,9}";
  char* p;
  Serial.println("Example of splitting a string into tokens: ");
  Serial.print("The input string is: '");
  Serial.print(str);
  Serial.println("'");

  p = strtok(str, "{,}"); //2nd argument is a char[] of delimiters
  while (p != '\0') { //not equal to NULL
    Serial.println(p);
    p = strtok('\0', "{,}");  //expects NULL for string on subsequent calls
  }
}

void loop() {
  delay(250);
}

Make sure the serial baud rates in code and the serial monitor are the same.

Thanks for the reply's on this page, https://www.hackster.io/HackingSTEM/stream-data-from-arduino-into-excel-f1bede

here is the code on that page and how would i get the for example the first piece and second piece of data and put them into a int ( int firstPiece = firstPiecefromString).....?

// ----------------------------------------------------------------------------
// Sample Sensor Code for use with Data Streamer Excel add-in
// more info available from Microsoft Education Workshop at 
// http://aka.ms/hackingSTEM 
// 
// This project uses an Arduino UNO microcontroller board. More information can
// be found by visiting the Arduino website: 
// https://www.arduino.cc/en/main/arduinoBoardUno 
//  
// This code reads in a generic analog sensor on Arduino pin 0 and prints 
// it to serial.
// 
// Comments, contributions, suggestions, bug reports, and feature requests 
// are welcome! For source code and bug reports see: 
// http://github.com/[TODO github path to Hacking STEM] 
// 
// Copyright 2019, Jen Fox Microsoft EDU Workshop - HackingSTEM 
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
// SOFTWARE. 
// ----------------------------------------------------------------------------

// Program variables ----------------------------------------------------------
int exampleVariable = 0;
int sensorPin = A0;

// Serial data variables ------------------------------------------------------
//Incoming Serial Data Array
const byte kNumberOfChannelsFromExcel = 6; 

// Comma delimiter to separate consecutive data if using more than 1 sensor
const char kDelimiter = ',';    
// Interval between serial writes
const int kSerialInterval = 50;   
// Timestamp to track serial interval
unsigned long serialPreviousTime; 

char* arr[kNumberOfChannelsFromExcel];

// SETUP ----------------------------------------------------------------------
void setup() {
  // Initialize Serial Communication
  Serial.begin(9600);  
}

// START OF MAIN LOOP --------------------------------------------------------- 
void loop()
{
  // Gather and process sensor data
  processSensors();

  // Read Excel variables from serial port (Data Streamer)
  processIncomingSerial();

  // Process and send data to Excel via serial port (Data Streamer)
  processOutgoingSerial();

// Compares STR1 to STR2 returns 0 if true.
//   if ( strcmp ("Apple", arr[0]) == 0){ 
//       Serial.println("working");
//   }
}

// SENSOR INPUT CODE-----------------------------------------------------------
void processSensors() 
{
  // Read sensor pin and store to a variable
  exampleVariable = analogRead( sensorPin );
  
  // Add any additional raw data analysis below (e.g. unit conversions)
  
}

// Add any specialized methods and processing code below


// OUTGOING SERIAL DATA PROCESSING CODE----------------------------------------
void sendDataToSerial()
{
  // Send data out separated by a comma (kDelimiter)
  // Repeat next 2 lines of code for each variable sent:

  Serial.print(exampleVariable);
  Serial.print(kDelimiter);
  
  Serial.println(); // Add final line ending character only once
}

//-----------------------------------------------------------------------------
// DO NOT EDIT ANYTHING BELOW THIS LINE
//-----------------------------------------------------------------------------

// OUTGOING SERIAL DATA PROCESSING CODE----------------------------------------
void processOutgoingSerial()
{
   // Enter into this only when serial interval has elapsed
  if((millis() - serialPreviousTime) > kSerialInterval) 
  {
    // Reset serial interval timestamp
    serialPreviousTime = millis(); 
    sendDataToSerial(); 
  }
}

// INCOMING SERIAL DATA PROCESSING CODE----------------------------------------
void processIncomingSerial()
{
  if(Serial.available()){
    parseData(GetSerialData());
  }
}

// Gathers bytes from serial port to build inputString
char* GetSerialData()
{
  static char inputString[64]; // Create a char array to store incoming data
  memset(inputString, 0, sizeof(inputString)); // Clear the memory from a pervious reading
  while (Serial.available()){
    Serial.readBytesUntil('\n', inputString, 64); //Read every byte in Serial buffer until line end or 64 bytes
  }
  return inputString;
}

// Seperate the data at each delimeter
void parseData(char data[])
{
    char *token = strtok(data, ","); // Find the first delimeter and return the token before it
    int index = 0; // Index to track storage in the array
    while (token != NULL){ // Char* strings terminate w/ a Null character. We'll keep running the command until we hit it
      arr[index] = token; // Assign the token to an array
      token = strtok(NULL, ","); // Conintue to the next delimeter
      index++; // incremenet index to store next value
    }
}

I think i got it now actually. The "token" holds the temporary value so i have to grap it with maybe the strcpy function and put it into a static variable. Correct me if i am wrong. I am definitely not a pro :slight_smile:

Is there an endmarker in your data (e.g. a line feed)? If so, mix Robin's recvWithEndMarker() example with the example that you're currently using. If there is no endmarker, it will be a little more complicated as you have to make sure that you always receive full packets (16 fields) and that the first field is indeed the first field.

Correct; you can also use pointers. If you however want to work with the floats, it's probably better to immediately convert it to a variable of type float.

why not convert it to int or float immediately

12.30
23.00
45.60
345.00
67.00
#define MAX_TOKS   10
char * toks [MAX_TOKS];
float  vals [MAX_TOKS];

int
tokenize (
    char *t )
{
    char s [80];
    int  i = 0;

    printf ("%s: %s\n", __func__, s);

    strcpy (s, t);

    for (toks [i] = strtok (s, ","); toks [i]; )  {
        vals [i] = atof (toks [i]);
        toks [++i] = strtok (NULL, ",");
    }

    return i;
}

// -----------------------------------------------------------------------------
const char t [] = "12.3,23,45.6,345,67";

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

    int nTok = tokenize ((char*) t);

    for (int n = 0; n < nTok; n++)
        Serial.println (vals [n]);
}

void
loop (void)
{
}

Thanks Everyone for helping me out! Here is my working code that got implemented into the industrial sheet metal shear in our factory.

int ExcelsheetQty=0;
float sheetStripData[100];
const byte kNumberOfChannelsFromExcel = 6; 
char* arr[kNumberOfChannelsFromExcel];

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

void loop()
{
processIncomingSerial();
}





void processIncomingSerial(){
  if(Serial.available()){
  static char inputString[64]; // Create a char array to store incoming data
  memset(inputString, 0, sizeof(inputString)); // Clear the memory from a pervious reading
  while (Serial.available()){
    Serial.readBytesUntil('\n', inputString, 64); //Read every byte in Serial buffer until line end or 64 bytes
  }
    char *token = strtok(inputString, ","); // Find the first delimeter and return the token before it
    ExcelsheetQty= atoi(token);
    Serial.print("ExcelsheetQty ");
    Serial.println(ExcelsheetQty);
    int index = 0; // Index to track storage in the array
    while (token != NULL){ // Char* strings terminate w/ a Null character. We'll keep running the command until we hit it
      arr[index] = token; // Assign the token to an array
      token = strtok(NULL, ","); // Conintue to the next delimeter
      sheetStripData[index]= atof(token);     // convert this part to a float      //////i also use index for my sheetstrip pointer
      Serial.print("index # is ");
      Serial.print(index);
      Serial.print(" and the value is ");
      Serial.println(sheetStripData[index]);
      index++; // incremenet index to store next value
    }
   }
  }

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