Arduino + Serial.parseInt()

Hey there!

I found some really useful code online to allow me to read multiple digit integers from the Serial monitor.
But i want to make it work with multiple multi-digit numbers seperated by a comma and stored in different variables.

here's the code:

void setup() {
  Serial.begin(9600);
}
 
 int integerValue=0; 
 
                              // Max value is 65535
char incomingByte;
 
void loop() {
  if (Serial.available() > 0) {   // something came across serial
    integerValue = 0;         // throw away previous integerValue
    while(1) {            // force into a loop until 'n' is received
      incomingByte = Serial.read();
      if (incomingByte == '\n') break;   // exit the while(1), we're done receiving
      if (incomingByte == -1) continue;  // if no characters are in the buffer read() returns -1
      integerValue *= 10;  // shift left 1 decimal place
      // convert ASCII to integer, add, and shift left 1 decimal place
      integerValue = ((incomingByte - 48) + integerValue);
      
    }
   Serial.println(integerValue);
   
  }
}

How would i go about to doing so?
Say the Serial Monitor input is : 123,456

i want it to be stored in two values so that
Var1 = 123
Var2 = 456

Thank you!!

Instead of using 2 variables, you should use an array and a counter instead. Then you can check if the incoming value is not a comma, store it into the array, if it is a comma, increment the counter.

The program you posted does not actually use the Serial.parseInt() function so I am intrigued by the thread title.

As it stands the program stops reading input when a Newline character is received. As a strart to answering your question you could perhaps change

if (incomingByte == '\n') break;   // exit the while(1), we're done receiving

to exit the (very clumsy) while(1) loop if either a Newline or a comma is received. You could then increment a counter to give you a value to test to determine which variable the number received should be stored in. As has been suggested this could usefully be in an array but that is up to you.

Note that the above suggestion is based on your current code which is not the best way to do what you want. Why, for instance have the while(1) loop when the loop() function provides the same mechanism ?

You could read all of the input at one time using Serial.readByteUntil('\n', buffer, maxLenght) and then use strtok() to pull out the individual numbers.

Thank you guys!
The while loop is so only that part of the code runs until the arguments are fufilled and then it breaks out and runs the rest of the code .

I dont quite understand what you mean by using a counter.

lele_gricc:
Thank you guys!
The while loop is so only that part of the code runs until the arguments are fufilled and then it breaks out and runs the rest of the code .

You could do stuff outside of the loop() function once the appropriate conditions are met. Doing it that way you can also do other things in the loop() function that would be impossible using while(1) because that would prevent other code being executed.

I dont quite understand what you mean by using a counter.

Initialise a variable to use as a counter to zero before reading the input. Every time you finish reading in a value that you want to save, use the value of the counter to decide where to save it and increment the counter ready for the next input and the next storage decision. The counter can conveniently be used as the index to an array of that is what you decide to use.

Is this what you meant (sort of)?

Its not really working what should i change?

int cnt = 0

void setup() {
  Serial.begin(9600);
}
 
 int integerValue=0; 
 
 char storedData[2];
                              // Max value is 65535
char incomingByte;
 
void loop() {
  if (Serial.available() > 0) {   // something came across serial
    integerValue = 0;         // throw away previous integerValue
    while(1) {            // force into a loop until 'n' is received
      incomingByte = Serial.read();
      if (incomingByte == '\n') break;
      if (incomingByte == ','){
        cnt++;
        break;     
      }           // exit the while(1), we're done receiving
      if (incomingByte == -1) continue;  // if no characters are in the buffer read() returns -1
      integerValue *= 10;  // shift left 1 decimal place
           // convert ASCII to integer, add, and shift left 1 decimal place
      integerValue = ((incomingByte - 48) + integerValue);
      
    }
    
    storedData[cnt] = integerValue;
    
    Serial.println(storedData[cnt]);
   
  }
}

Try this amended version based on your code. I have commented the changes that I made

int cnt = 0;  // <<<<<<<<<  added the semi colon
int integerValue=0; 
int storedData[2];    //<<<< the value to be stored is an int but only space for 2 of them as written
// Max value is 65535
char incomingByte;


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

void loop() 
{
  if (Serial.available() > 0) {   // something came across serial
    integerValue = 0;         // throw away previous integerValue
    while(1) {            // force into a loop until 'n' is received
      incomingByte = Serial.read();
      if (incomingByte == '\n' || incomingByte == ',') //<<<<<<<<< break on Newline or comma
      {
        break;     
      }           // exit the while(1), we're done receiving
      if (incomingByte == -1) continue;  // if no characters are in the buffer read() returns -1
      integerValue *= 10;  // shift left 1 decimal place
      // convert ASCII to integer, add, and shift left 1 decimal place
      integerValue = ((incomingByte - 48) + integerValue);
    }
    storedData[cnt] = integerValue;
    Serial.println(storedData[cnt]);
    cnt++;      //<<<<<<<<<<<<<<<increment index after storing and printing
  }
}

The below code does something similar to what you might want to do.

//zoomkat 11-12-13 String capture and parsing  
//from serial port input (via serial monitor)
//and print result out serial port
//copy test strings and use ctrl/v to paste in
//serial monitor if desired
// * is used as the data string delimiter
// , is used to delimit individual data 

String readString; //main captured String 
String angle; //data String
String fuel;
String speed1;
String altidude;

int ind1; // , locations
int ind2;
int ind3;
int ind4;
 
void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 11-12-13"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like 90,low,15.6,125*
  //or 130,hi,7.2,389*

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == '*') {
      //do stuff
      
      Serial.println();
      Serial.print("captured String is : "); 
      Serial.println(readString); //prints string to serial port out
      
      ind1 = readString.indexOf(',');  //finds location of first ,
      angle = readString.substring(0, ind1);   //captures first data String
      ind2 = readString.indexOf(',', ind1+1 );   //finds location of second ,
      fuel = readString.substring(ind1+1, ind2+1);   //captures second data String
      ind3 = readString.indexOf(',', ind2+1 );
      speed1 = readString.substring(ind2+1, ind3+1);
      ind4 = readString.indexOf(',', ind3+1 );
      altidude = readString.substring(ind3+1); //captures remain part of data after last ,

      Serial.print("angle = ");
      Serial.println(angle); 
      Serial.print("fuel = ");
      Serial.println(fuel);
      Serial.print("speed = ");
      Serial.println(speed1);
      Serial.print("altidude = ");
      Serial.println(altidude);
      Serial.println();
      Serial.println();
      
      readString=""; //clears variable for new input
      angle="";
      fuel="";
      speed1="";
      altidude="";
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

Here's a working example

String concatStr;
int myValues[10];
byte counter;

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

void loop() 
{
  while(Serial.available())
  {
    char c = Serial.read();    

    if( c == 'p' ) //Press p to print array
    {
      for(int i=0;i<counter;i++)
      {
        Serial.println(myValues[i]);
      }
    }
    else if( c == ',' )
    {  
      if( counter == 10 )  //Array size is set to 10, when full, reset and redo
      {
        memset(myValues, 0, sizeof(myValues));
        counter = 0;
      }    
      
      myValues[counter]=concatStr.toInt();
      Serial.print("Added ");
      Serial.println(myValues[counter]);
      counter++;
      concatStr = "";
    }
    else
    {
      concatStr += c;
    }
  }
}

Your input must end with a ,(comma). You can access your 1st, 2nd, values using myValues[0], myValues[1], etc

For zoomkat how would i go about comparing the numbers recieved ?

Say i wanted to check that fuel was more than angle... how would i do so since they are strings?

const int MAX_LEN = 80;
const char lineEnding = '\n'; // whatever marks the end of your input.
char inputSentence [MAX_LEN + 1];
int inputIndex;
bool newInput;

const byte MAX_TOKENS = 4;
const char* delimiters = ", "; // whatever characters delimit your input string
char* tokens [MAX_TOKENS + 1];
enum indexName {angle, fuel, speed, altitude};
#define PRINT_ITEM(x) printItem (x, #x)

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

void loop ()
{
 if (newInput && strlen (inputSentence))
 {
   int tokenIndex = 0;
   Serial.println (inputSentence); // tell 'em what you've got
   tokens [tokenIndex] = strtok (inputSentence, delimiters);
   while ((tokenIndex < MAX_TOKENS - 1) && tokens [tokenIndex])
   {
     tokenIndex++;
     tokens [tokenIndex] = strtok (NULL, delimiters);
   }
   
   PRINT_ITEM (angle);
   PRINT_ITEM (fuel);
   PRINT_ITEM (speed);
   PRINT_ITEM (altitude);

   // reset things for the next lot.
   newInput = false;
   inputIndex = 0;
   inputSentence [0] = '\0';
 }
}

void serialEvent ()  // build the input string.
{
 while (Serial.available() )
 {
   char readChar = Serial.read ();
   if (readChar == lineEnding)
   {
     newInput = true;
   }
   else
   {
     if (inputIndex < MAX_LEN)
     {
       inputSentence [inputIndex++] = readChar;
       inputSentence [inputIndex] = '\0';
     }
   }
 }
}

void printItem (int index, char* name)
{
 Serial.print (name);
 Serial.print (F(" "));
 Serial.println (tokens [index]);  
}

This source is the same length as zoomkat's, but compiles to about half the memory.
A simple "atoi" would convert the strings to integers that could then be compared.
No mucking about with nasty Strings.

As i am new to coding i barely understand what is happening in your code AWOL, and for now memory is not an issue even though i know its good habit.

Also for ZoomKats code could i just the toInt() function to make them integers for comparing?

In my code the sent characters are captured as a String and not a c-string. The below link has the String functions detailed out. Your "fuel was more than angle" is not very clear. With the String functions character strings can be compared. If what you want to compare are numerical values, then the captured numerical character string would need to be converted into a number and the usual numeric comparison functions >, <, ==, etc. could be used.

for now

Keep that in mind when it does become an issue.

I know its just that i dont understand his complex code and i dont like using code i dont understand.

I found this simple code on a book I am reading for learning

int led = 13;
void setup(){
 pinMode(led, OUTPUT);
 Serial.begin(9600);
}
void loop(){
 if (Serial.available()){
 char com = Serial.read();
 // Act according to the value received
 if (com == 'x'){
 // Stop the LED
 digitalWrite(led, LOW);
 }
 else if (com == 'a'){
 // Start the LED
 digitalWrite(led, HIGH);
 }
 else if (com == 'b'){
 // Blink with a delay corresponding to the value received after 'b'
 if (Serial.peek() > '0' && Serial.peek() <= '9'){
 digitalWrite(led, HIGH);
 delay((Serial.read() - 48) * 100);  // 48 is ASCII for '0'
 digitalWrite(led, LOW);
 }
 }
 }
}

I tried with my board but doesn't work...
I changed it after a lot of googling, like this.

int led = 13;
int x;
String str;

void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0)
  {
    str = Serial.readStringUntil('\r');
    x = Serial.parseInt(char 'b');
  }


  // Act according to the value received
  if (str == "x") {
    // Stop the LED
    digitalWrite(led, LOW);
    Serial.println(str);
    str = "c"; //change value of str to avoid endless printing of x
  }
  else if (str == "a") {
    // Start the LED
    digitalWrite(led, HIGH);
    Serial.println(str);
    str = "c"; //change value of str to avoid endless printing of a
  }
  else if (str == "b") {

    digitalWrite(led, HIGH);
    delay(x * 100);  
    digitalWrite(led, LOW);
    Serial.print(str);
    Serial.println(x);
    str = "c"; //change value of str to avoid endless printing of b
  }
  // }
}

But still I cannot get my led blink.
Can anyone help me?
Why the first sketch does not work in the first place?
Thank you anyway.

    x = Serial.parseInt(char 'b');

This doesn't even compile, does it? The parseInt() method does not take any arguments.

I tried with my board but doesn't work...

What does it do when you run it ? What are you expecting it to do when you run it ?

lele_gricc:
For zoomkat how would i go about comparing the numbers recieved ?

Say i wanted to check that fuel was more than angle... how would i do so since they are strings?

Servo test code that receives a string numeric value as a String, and converts the numeric value into a number for a servo command. In your situation you could extract the numeric value, convert to a number, then make the greater/less than comparison.

//zoomkat 11-22-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added 
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 

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

  //myservoa.writeMicroseconds(1500); //set initial servo position if desired

  myservoa.attach(6);  //the pin for the servoa control
  myservob.attach(7);  //the pin for the servob control
  myservoc.attach(8);  //the pin for the servoc control
  myservod.attach(9);  //the pin for the servod control 
  Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}

void loop() {

  //expect single strings like 700a, or 1500c, or 2000d,
  //or like 30c, or 90a, or 180d,
  //or combined like 30c,180b,70a,120d,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
          if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.write(n);
          if(readString.indexOf('b') >0) myservob.write(n);
          if(readString.indexOf('c') >0) myservoc.write(n);
          if(readString.indexOf('d') >0) myservod.write(n);
        }
         readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}