Spliting serial strings, then convert to int

Sorry for what may be the hundredth one of these but everything I have found does not work for me (or I don't understand it, new to C++), or include c++ methods not on this.

I'm sending a string two numbers (both are only from 0 to 100) in a string like "15:65" from a c# program I have running. I simply want to do is split that into the two numbers and then convert them to an int.

Do you know what a case statement is? Normally I would say to use the strtok() function, which you still could, but that’s a little much for what your doing.

What you could do instead is use an IF statement to check if the value your receiving is a number or a colon. Once you can tell the difference, you can use case statements to collect the two numbers and convert them into ints. If you do get a semicolon, you can then switch the case statement and collect the values for the second number. Once you have both numbers and use them, you then need to clear them to start over for new data.

This is an example you can use to collect the data and convert it to an int.
Not the full code, it’s just an idea

char val = Serial.read();
if( val <= '0' || val >= '9' ) // val is NOT a digit
{
  CaseInc++; // will switch case if not a digit
}
// make case statement here
FirstNum = FirstNum * 10 + ( val - '0' ); // first number

So you mean like this:

if(Serial.available() > 0){
    char c = Serial.read();
    
    if(c <= '0' || c >= '9'){
      count++;
    }
    
    switch(count){
       case 1:
         t1 = t1 * 10 + (c - '0');
       break; 
       case 2:
         t2 = t2 * 10 + (c - '0');
       break;
    }
  }

Do I use While(serial.available) or if, As I do need the full value each loop?

Also how does the converting to int work, as im using LED’s and they go crazy with what’s on it now even when the serial input is “0:0”. Also wouldn’t it be “if(c < ‘0’ || c > ‘9’)” else I would not get numbers with 0 or 9?

That's fine, just make sure count = 1 (globally). The conversion method works like this. FirstNum starts at 0, then you get a value from the serial monitor, "c". Now because c is a char, you need it to be converted to an int, so (c - '0') does just that. Now "FirstNum = FirstNum * 10 + (c - '0')" takes single digits and meshes them together, into however large of a int or long.

Example: c = '5'; FirstNum = 0. 0 = 0 * 10 + ('5' - '0'); 0 = 0 * 10 + (5); by order of operations, multiplication is done first. 0 = 0 + 5;

Now FirstNum = 5. Get a new value. c = '9'; FirstNum = 5. 5 = 5 * 10 + ('9' - '0'); 5 = 5 * 10 + (9); by order of operations, multiplication is done first. 5 = 50 + 9; Now FirstNum = 59.

If your LEDs are going crazy, make sure your using the PWM (~)pins. If that still doesn't work, post your full code.

This is how it worked with a single serial number input:

// =====================================================
// DO NOT EDIT ABOVE

int clockPin = 13;
int dataPin = 11;

boolean leftToRight = true; // Does the LED stip start from Left side of the screen?
int nLEDs = 25; // Number of LED's 
boolean ColourSwapFade = false; // Do you want to  fade from colour to color (true), or from black into colour (false)
float sensitivity = 1.5; // Multiply the incoming volume level so lower sound levels create brighter light
int fadeAm = 7; // Fade speed

// Colour settings 
// > Fade colour, The colour you want to fade in with sound
int fadeColLeft[3] = { 255, 0, 0 };
int fadeColRight[3] = { 0, 0, 255 };

// DO NOT EDIT BELOW, UNLESS YOU KNOW WHAT YOU ARE DOING
// =====================================================

int rgb[3] = {0,0,0};
int rgb2[3] = {0,0,0};

int incomingByte = 0;
float a;

int t1,t2;

RGBLEDChain led(nLEDs, clockPin, dataPin);

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

void loop() {
  if (Serial.available() > 0) {
    incomingByte = Serial.parseInt();
  }
  
  /*
  int count = 0;
  t1 = 0;
  t2 = 0;
  
  if(Serial.available() > 0){
    char c = Serial.read();
    
    if(c <= '0' || c >= '9'){
      count++;
    }
    
    switch(count){
         case 1:
           t1 = t1 * 10 + (c - '0');
         break; 
         case 2:
           t2 = t2 * 10 + (c - '0');
         break;
      }
  }
  
  incomingByte = t2;*/

  fade();
  
  led.update();  
}

void fade(){
  for(int i=0;i<nLEDs;i++){
   rgb[0] = fadeInt(fadeColLeft[0],rgb[0]);
   rgb[1] = fadeInt(fadeColLeft[1],rgb[1]);
   rgb[2] = fadeInt(fadeColLeft[2],rgb[2]);
   
   FTLEDColour col = { rgb[0] , rgb[1] , rgb[2] };
   led.setLED(i, col);
 }
}

int fadeInt(int setlevel, int col){
  int tempa = (setlevel / 100) * (incomingByte * sensitivity);
  float temp = (col * fadeAm + tempa + fadeAm) / (fadeAm +1 );
  if(temp < 0) { return 0; } else { if(temp > 255) { return 255; } else { return temp; } }
}

Ok I see what your doing, but in this case, I’ll need to add a new line to the code I gave you. In order for this to work, you need to change your string to include a period at the end of it “XX:YY**.**”

Actually, I’ll change the code you provided.

if(Serial.available() > 0){
    char c = Serial.read();
    
    if(c <= '0' || c >= '9') 
    {
        count++;
    }

    if( c == '.') 
    {
        count = 0; t1 = 0; t2 = 0; // if the received char is a period, reset count and t1,t2 back to zero
     }
    
    switch(count){
       case 0:
         t1 = t1 * 10 + (c - '0');
       break; 
       case 1:
         t2 = t2 * 10 + (c - '0');
       break;
    }
  }

This is no longer needed. Change incomingByte the way you were going to.

if (Serial.available() > 0) {
incomingByte = Serial.parseInt();
}

Thanks, But this still doesnt seem to work how i want it to, This is with single input: https://www.youtube.com/watch?v=d-hXV7nvkkU&feature=player_detailpage#t=54

And with the new: https://www.youtube.com/watch?v=dY8tu4_J2ZA&feature=youtu.be

The audio is always above 30 so it should never go black. My program is writing to the serial port every 15ms if that makes any differance.

EDIT: Also it seems to have a delay of 1s from my program sending the levels to the lights changing.

What string were you sending that gave both red and blue to show?

When I tested my code, I noticed it was adding the colon to the second number, this should take care of that.

int count= 0, t1= 0,t2= 0;
void setup(){
  Serial.begin(9600);
}

void loop() {
  if(Serial.available() > 0){
    char c = Serial.read();

    if(c == '.') // if c is a period, show data and clear everything
    {
      showme(t1,t2);  // Replace with  fade(); & led.update();  
      count = 0; 
      t1 = 0; 
      t2 = 0; // if the received char is a period, reset count and t1,t2 back to zero
    }

    if(c == ':') // if c is a colon, change cases
    {
      count++;
    }

    else  // same as "if(c >= '0' || c <= '9')"
    {
      if(c != '.') // if c is a period, do NOT add it to t1 or t2, discard it!
      {
        switch(count){
        case 0:
          t1 = t1 * 10 + (c - '0');
          break; 
        case 1:
          t2 = t2 * 10 + (c - '0');
          break;
        }
      }
    } 
  }
}

void showme( int D1, int D2){
  Serial.print("D1: ");
  Serial.print(D1 );
  Serial.print(" : ");
  Serial.print("D2: ");
  Serial.println(D2);
}

Well im probably screwing something up, But T1 comes in wrong, All i changed was:

if(c == '.') // if c is a period, show data and clear everything
    {
      fade();
      led.update(); 
      Serial.println(t1);
      count = 0; 
      t1 = 0; 
      t2 = 0; // if the received char is a period, reset count and t1,t2 back to zero
    }

And T1 comes back as:

Im sending it as:

port.WriteLine(l+":"+r+".");

See what the raw data is going to the arduino.

If you meant print in what was coming in, this came back:

Are you sending a string of chars or ints? See what happens if you change c to int instead of char and take away " - '0' "

I'm putting it in as a string via this method http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.writeline%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

When changed to int it returns completely wrong values.

I think the issue here is the difference between Strings and strings. One is a string object the other is an array of chars. You might need to use another method than what I gave you.

Does it work with the Arduino serial monitor? Try it with just entering the string into the Arduino serial monitor and see if it works or not. What I gave you is meant for char arrays not Strings.

Post both codes if you can.

Ah i see, I fixed it by chaning my c# program to send like this:

string start = l + ":" + r + ".";
char[] end = start.ToCharArray();

port.Write(new string(end));

And seems to work perfectly now: https://www.youtube.com/watch?v=M7JExl68Kh0&feature=youtu.be

Thanks for all the help.

All good now? Could you make a video, I would love to see it.

Here: https://www.youtube.com/watch?v=vS3JJxMosvM

Not the best video due to camera phone, Currently working on colour fading option instead of Black -> colour... But for some reason the first colour works fine but always fades to pink. As seen here: https://www.youtube.com/watch?v=kH0jMELv-xk

If you can, see what the actual value is that's going to the LEDs.

Got it working: https://www.youtube.com/watch?v=lbk2i-5egXs

And thanks again for all the help.

Your welcome.