Read line from Serial

Hello,

I want to be able to control a RGB led over serial by writing different Analog values.
The problem is that Serial.read() only returns one value a time.

What would be the best method to process data which is sent like:
r=0
g=255
b=255

What would be the best method to process data which is sent like:

One character at a time.

PaulS:

What would be the best method to process data which is sent like:

One character at a time.

Yes, I could save these characters in a buffer, but how will I be able to convert the buffer to a int which can be used for PWM.

null terminate it and use atoi

You can capture the values as a string, and then convert the string into a number. The below shows how to capture a string and convert it into a number for use for servo control. If you can attach a delimiter to each value sent to keep the values seperate (like using a comma, 254,128,200,90,), then possibly simpler code can be used.

// zoomkat 12-13-11 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 1.0
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550
// use serial monitor to test

#include <Servo.h> 
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo 
Servo myservo2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(6);  //the pin for the servo control 
  myservo2.attach(7);
  Serial.println("two-servo-test-1.0"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(3);  //delay to allow buffer to fill 
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    } 
  }

  if (readString.length() >0) {
      Serial.println(readString); //see what was received
      
      // expect a string like 07002100 containing the two servo positions      
      servo1 = readString.substring(0, 4); //get the first four characters
      servo2 = readString.substring(4, 8); //get the next four characters 
      
      Serial.println(servo1);  //print to serial monitor to see parsed results
      Serial.println(servo2);

      int n1 = servo1.toInt();
      int n2 = servo2.toInt();

      Serial.println("the numbers are :");
      Serial.println(n1);  //print to serial monitor to see number results
      Serial.println(n2);
            
      myservo1.writeMicroseconds(n1); //set servo position 
      myservo2.writeMicroseconds(n2);
    readString="";
  } 
}

'readString' was not declared in this scope
How to solve it?

thenamefirst:
'readString' was not declared in this scope
How to solve it?

You probably messed something when selecting / coping, here it works out of the box.

Personally, I would use strtok. Read and buffer the entire line, then parse it, something like this (untested...):

char buffer [32];
int cnt = 0;
boolean ready = false;
int rgbval, red, green, blue;

void ParseLine
{
char key[8];
char value[8];

    key = strtok(buffer, "=");    // Everything up to the '=' is the color name
    value = strtok(NULL, "\n");  // Everything else is the color value
    if ((key != NULL) && (value != NULL))
    {
        rgbval = atoi(value);
        switch (toupper(key))
        {
            case 'R'
                red = rgbval;
                break;
            case 'G'
                green = rgbval;
                break;
            case 'B'
                blue = rgbval;
                break;
        }
    }
}

void loop()
{
    if (ready)
    {
        ParseLine();
        ready = false;
    } else while (Serial.available())
    {
        char c = Serial.read();
        buffer[cnt++] = c;
        if ((c == '\n') || (cnt == sizeof(buffer)-1))
        {
            buffer[cnt] = '\0';
            cnt = 0;
            ready = true;
        }
    }
}

thx

The examples in serial input basics should do what you need.

...R

1 Like

why i adapt this code to use like this:
#include <Servo.h>
#include <SPI.h>
#include <SD.h>
const int chipSelect = 4;
File myFile;
String readString, servo1, servo2;

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

while (!Serial)
{
; //
}
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
myFile = SD.open("FIRST1.txt");
if (myFile)
{
Serial.println("FIRST1.txt:");
}
else
{
Serial.println("error opening test.txt");
}
}

void loop() {
myFile = SD.open("LL.txt");
if (myFile){
delay(3); //delay to allow buffer to fill
if (myFile.available() >0) {
char c = myFile.read(); //gets one byte from serial buffer
readString += c; //makes the string readString
}
if (readString.length() >0) {
Serial.println(readString); //see what was received

}
}

}
and my SD card have 12345678 data
but the result was
1
11
111
1111
11111
111111
1111111

thenamefirst:
why i adapt this code to use like this:

What do you mean by "this" ? What was the original code before you changed it?

...R

Greetings.

Try this code

#define red  9
#define green 10
#define blue 11

int tblue = 0;
int tgreen = 0;
int tred = 0;

void setup() {
  pinMode(blue, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  Serial.begin(115200);
  color(255,0,0);

}

void loop() {
  if(Serial.available()>0){
    tred=Serial.parseInt();
    tgreen=Serial.parseInt();
    tblue=Serial.parseInt();
    color(tred,tgreen,tblue);
    Serial.println("red " + (String)tred + " green  " + (String)tgreen + " blue " + (String)tblue);
  }
 
}


void color(int cred, int cgreen, int cblue) {
  analogWrite(red, cred);
  analogWrite(green, cgreen);
  analogWrite(blue, cblue);
}

Sending 0,255,255 for r,g,b

the original code is #4 i change it to read data from SD card.
my SD card data is 12345678
but when i use #10 code the result is
1
11
111
1111
11111
111111

myFile = SD.open("LL.txt");
  if (myFile){
    delay(3);  //delay to allow buffer to fill
    if (myFile.available() >0) {

That delay is just plain stupid. The SD.open() function doesn't return until the associated buffer has been filled.

Then, you read one character from the file, append it to the String instance, print the string, end loop(), and open the file again.

The if in the snippet above needs to be a while, to read the whole file.

I would suggest using Serial.readStringUntil("\n") which waits until the carriage return character is read or the end of the timeout.

foadsf:
I would suggest using

Serial.readStringUntil("\n")

which waits until the carriage return character is read or the end of the timeout.

Error:

invalid conversion from 'const char*' to 'char' [-fpermissive]

Need to use single instead of double quotes for only one character, this works:

String inputString = Serial.readStringUntil('\n');

See too:

foadsf:
I would suggest using Serial.readStringUntil("\n") which waits until the carriage return character is read or the end of the timeout.

I would advise not to promote the use of String (capital S) objects; there is the risk of memory fragmentation which might result in unpredictable run time behaviour. readBytesUntil is a far better option and Robin's Serial Input Basics tutorial is far preferred.

Note
This thread is 7 years old

1 Like