My Serial doesn't work like I want it to...

Ok, so I've run into my first real confusing issue ever since I got my Arduino. I'm trying to make an RGB controllable via Serial commands (through the Serial Monitor). I'm sure this has been done before, but I like to learn as a go, and prefer not to use tutorials :). I'm still quite a "noob" at this, so I may be doing something completely wrong. As it is now, the code should receive something like "B/R/G255/Any other 0-255 value", ie "G127". I then have it successfully take the first letter, and store it in a variable called "incoming".

I then try to store the next byte (0-255) in a specific variable depending on the first letter, which kind of works. The "value" gets stored in the correct variable, but strangely.

When I Serial.print() the value, I get something in the range of 48-55 no matter what I type, and I have no clue why. Then, if I try to analogWrite() it to the corresponding pin of the LED, it just turns on (seemingly) fully. (Maybe it's just mostly on...see my last paragraph before the code..)

In case you're wondering why I'm apparently turning on all colors fully at the beginning, I'm not, this is a common anode LED, and therefore I'm making sure they're all off. (0 = full on and 255 = full off)

Here's the code:

const int red = 3;
const int green = 5;
const int blue = 6;
int redVal = 0;
int greenVal = 0;
int blueVal = 0;
char incoming = 0;

void setup() {
  Serial.begin(9600);
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  analogWrite(red, 255);
  analogWrite(green, 255);
  analogWrite(blue, 255);
}

void loop() {
  if (Serial.available()) {
    delay(100);
    incoming = Serial.read();
    if (incoming == 'r' || incoming == 'R') {
      redVal = Serial.read();
      delay(100);
      Serial.println(redVal);
    }
      if (incoming == 'g' || incoming == 'G') {
        greenVal = Serial.read();
        delay(100);
        Serial.println(greenVal);
      }
        if (incoming == 'b' || incoming == 'B') {
        blueVal = Serial.read();
        delay(100);
        Serial.print(blueVal);
        }
  }
}

Thanks for reading :P.

Two things...

  1. I suggest flipping the number and the letter (e.g. "127G" instead of "G127"). Doing this will simplify your code. In case you're really interested, your code would become what's called a (almost) stateless parser.

  2. The data sent to the Arduino is a string of ASCII characters. You will have to convert them to a binary number. There are at least a few examples on this forum. I suspect that you'll find exactly what you need after a few minutes of searching.

Your computer sends characters and numbers in ASCII encoded form, which is not the same as binary.

Every character is associated with a certain binary number. It so happens that the characters for 0,1,2,....,9 are encoded like this:

0: 48 1: 49 2: 50 3: 51 .... 9: 57

So if you press say 5 on your keyboard, the arduino will receive a byte containing the number 53 (in decimal).

To send a string like G127 you need to read 4 bytes on the arduino side.

To convert ASCII numbers to 'real' numbers you can do sth. like this:

byte number = number_read - '0';

This subtracts the appropriate ASCII number for zero (which is 48) from what you've received and the variable becomes 0 in this case.

Thanks for the replies, I just have one more question. How do I combine all three numbers into a single variable? Ie, 2, 5, & 5 should be 255, and not 12.

Read the 2. Store it. Read the 5. Multiply the stored value by 10. Add the new digit.

Rinse and repeat.

Read the 2. Store it. Read the 5. Multiply the stored value by 10. Add the new digit.

Rinse and repeat.

Ah, smart. I was thinking it was going to be something weird like bit shift :P. Thanks :).

I was thinking it was going to be something weird like bit shift

That can work too - shift left 1 place, store it as a temporary, shift two more places left and add in the temporary. Voila - x10.

That can work too - shift left 1 place, store it as a temporary, shift two more places left and add in the temporary. Voila - x10.

True. I'll just stick with my "lazy" version..The one I can grasp right after waking up ;D!

Huzzah it’s all working now :). I got lazy and just stuck with the letter than value way of doing it. Also, I made it so entering 0 sets the value to 255, because this is a common anode LED, and I was getting confused :P.

IE, entering 0 will turn off the LED, and entering 255 will turn that color full on.

Here’s the code:

const int red = 3;
const int green = 5;
const int blue = 6;
int redIncoming[3] = {0, 0, 0};
int greenIncoming[3] = {0, 0, 0};
int blueIncoming[3] = {0, 0, 0};
int redVal = 0;
int greenVal = 0;
int blueVal = 0;
char incoming = 0;

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

void loop() {
  if (Serial.available()) {
    delay(100);
    incoming = Serial.read();
    if (incoming == 'r' || incoming == 'R') {
      redIncoming[1] = 0;
      redIncoming[2] = 0;
      redIncoming[3] = 0;
      redVal = 0;
      while (Serial.available() > 0) {
        for (int i = 0; i <3; i++) {
          redIncoming[i] = Serial.read();
          if (redIncoming[i] != -1) {
            redIncoming[i] = (redIncoming[i] - '0');
            redVal = (redVal * 10) + redIncoming[i];
          }
        }
      }
      incoming = 0;
      delay(100);
      redVal = map(redVal, 255, 0, 0, 255);
      analogWrite(red, redVal);
      Serial.print("Red set to ");
      Serial.println(redVal);
    }
      if (incoming == 'g' || incoming == 'G') {
      greenIncoming[1] = 0;
      greenIncoming[2] = 0;
      greenIncoming[3] = 0;
      greenVal = 0;
      while (Serial.available() > 0) {
        for (int i = 0; i <3; i++) {
          greenIncoming[i] = Serial.read();
          if (greenIncoming[i] != -1) {
            greenIncoming[i] = (greenIncoming[i] - '0');
            greenVal = (greenVal * 10) + greenIncoming[i];
          }
        }
      }
      incoming = 0;
      delay(100);
      greenVal = map(greenVal, 255, 0, 0, 255);
      analogWrite(green, greenVal);
      Serial.print("Green set to ");
      Serial.println(greenVal);
      }
        if (incoming == 'b' || incoming == 'B') {
      blueIncoming[1] = 0;
      blueIncoming[2] = 0;
      blueIncoming[3] = 0;
      blueVal = 0;
      while (Serial.available() > 0) {
        for (int i = 0; i <3; i++) {
          blueIncoming[i] = Serial.read();
          if (blueIncoming[i] != -1) {
            blueIncoming[i] = (blueIncoming[i] - '0');
            blueVal = (blueVal * 10) + blueIncoming[i];
          }
        }
      }
      incoming = 0;
      delay(100);
      blueVal = map(blueVal, 255, 0, 0, 255);
      analogWrite(blue, blueVal);
      Serial.print("Blue set to ");
      Serial.println(blueVal);
        }
  }
}

What is the purpose of saving data in the redIncoming, greenIcoming, anf blueIncoming arrays? You never actually use those array.

What is the purpose of saving data in the redIncoming, greenIcoming, anf blueIncoming arrays? You never actually use those array.

Er...

 redIncoming[i] = Serial.read();
          if (redIncoming[i] != -1) {
            redIncoming[i] = (redIncoming[i] - '0');
            redVal = (redVal * 10) + redIncoming[i];
          }

I suppose it could be done with one variable? :P

Yes, it could. That was my point.