0

All good afternoon or evening. I am having a problem writing a sketch for Arduino using Arduino UNO and Bluetooth HC - 06.

My program does not divide the input stream of information into several variables. No matter how many variables I specify, they are considered as one.

Maybe I do not know all subtleties of the use of Serial.read(). Apparently from a sketch given below I get through Bluetooth two variables of color and var. A microcontroller perceives these two variables as one and as a result does not execute before him task. As a result we will be able to choose the color and change delay of blinking by this color.

If anybody knows how to correct this problem or can point me to a similar project I will be very thankful for any rendered help

const int rPin = 3;
const int gPin = 5;
const int bPin = 6;
int chosed_color;
int val; 
int color;

void setup() 
{
  Serial.begin(9600);
  pinMode( rPin, OUTPUT );
  pinMode( gPin, OUTPUT );
  pinMode( bPin, OUTPUT );

}

void loop() 
{
while(Serial.available()>0)
  {
     color = Serial.read();
   if(color==1)
      {
       chosed_color = rPin;
      digitalWrite( rPin, HIGH );       
      digitalWrite(rPin, LOW);  
       return chosed_color;
      }
        else if(color==2)
      {
       chosed_color = bPin;
       digitalWrite( bPin, HIGH );     
      digitalWrite(bPin, LOW);  
       return chosed_color;
      }
         else if(color==3)
      {
        chosed_color = gPin;
       digitalWrite( gPin, HIGH );
       digitalWrite(gPin, LOW);  
       return chosed_color;
      }
  }
if(Serial.available()>0) 
{
  val = Serial.read();
}

      digitalWrite( rPin, HIGH );
      delay(val);       
      digitalWrite(rPin, LOW);  
      delay(val); 
}
1

Your code have various issues.

This:

   if(color==1)
      {
       chosed_color = rPin;
      digitalWrite( rPin, HIGH );       
      digitalWrite(rPin, LOW);  
       return chosed_color;
      }

means that when you find a color, you exit loop() instead of reading the val variable.

Serial.read

Serial.read read only one byte. If you need to read an arbitrary integer, need Serial.parseInt or some elaborate solution. As it, you are only able to read one-digit integer values.

Worse, when you type "1" in the Serial Monitor, what the program received is the value 49 (the ascii code for char 1).

Also, you have to filter non interesting chars, like LF, CR, commas or whatever char you use as delimitir.

Please, read the excelent post by Majenko about Reading Serial on the Arduino.

Here a better version of your code. It is very basic and lacks all error checking, etc.

const int rPin = 3;
const int gPin = 5;
const int bPin = 6;
int pins[3] = {rPin, gPin, bPin};

void setup()
{
    Serial.begin(9600);
    pinMode(rPin, OUTPUT);
    pinMode(gPin, OUTPUT);
    pinMode(bPin, OUTPUT);
}

void loop()
{
    if(Serial.available()>0) {
        int color = Serial.read();
        int chosed_color = pins[color-1];
        digitalWrite(chosed_color, HIGH);
        digitalWrite(chosed_color, LOW);

        if(Serial.available()>0) {
            int val = Serial.read();
            digitalWrite(chosed_color, HIGH); // I suppose you want this
            delay(val);
            digitalWrite(chosed_color, LOW);
            delay(val);
        }
    }
}
  • this code doesn't work. I agree that it is more perfect but I don't see any result. – Andrew Goroshko Feb 8 '18 at 15:33
  • @AndrewGoroshko. As I said, you have a lot to work to do. I just simplify your code (and some cleanup). For example, the code assume that val will be always available, but that is not always the case. Also, it doesn't taken in account the missing char to int conversion at Serial.read() ... if you write the char 1 at the Serial Monitor, your code receive 49. It's full of traps. Sorry – user31481 Feb 8 '18 at 15:42
  • I send int variable from my phone but not char, although I am so appreciate you for solving several my problems – Andrew Goroshko Feb 8 '18 at 15:48
1

You have a misconception, how serial communication works. The data is transmitted one byte at a time and not in one bunch (even if you type it in the Serial Monitor in as one string). So, when you use distinct if- or while-statements for each variable, the data may arrive at any step in these statements, without any possibility to distinguish between the variables.

You have to ways dealing with serial messages (I prefer the latter for it is more flexible):

  • Constant message length: You can always send messages with the same length. This is suitable for small projects with only one functionality, so that you always send the same amount of data. In this case you can wait for all bytes of a message to arrive and then treat the message as a whole:
if(Serial.available() >= 2){
  variable1 = Serial.read();
  variable2 = Serial.read();
}
  • Using a delimiter character for each message: After each message you can send an extra byte, which value you treat as a delimiter for a message. Normally with this method you save each available byte in an extra buffer, until you receive your delimiter character (often the newline character is used '\n'):
void setup(){
  String message="";
}

void loop(){
  while(Serial.available>0){
    char c = Serial.read();
    if(c == '\n'){
      // Message is complete in buffer variable
      // Extract values from it
      if(message.length>0){
        byte variable1 = message[0];
      }
      if(message.length>2){
        int variable2 = (message[1] << 8) | message[2];
      }
      // Reset buffer variable
      message = "";
    } else {
      // Message is not complete, add byte to buffer variable
      message += c;
    }
  }
}

As said in the other answers you have to decide, how to send numerical data.

  • You can send direct byte data as I used in the code above. When you are sending a bigger value to the Arduino than 1 byte, you can take the corresponding number of bytes from the buffer and put them into one variable (<< 8 shifts the byte data 8 bytes to the left (in the direction of the MSB); | makes a bytewise or, that puts the bytes together in this code).
  • If you want to type in values in the serial monitor, you have to consider, that these are simple ASCII encoded strings. In this case you can use the String.toInt() function and it's siblings on a substring of your message, that contains the numerical value.
0

Communication is done only with bytes. A byte is ALWAYS a numerical value and you cant' transmit more than one byte at a time. Saying that, you have two points to understand:

1) how do you want to "see" the result, from a human point of view?

2) how can you transmit more than one byte?

Just test this little sketch:

 void setup() {
Serial.begin(9600);
Serial.println(65);
Serial.println("65");
Serial.println("A");

Serial.write(65);
Serial.write('A');
}

void loop()
{
} 

You will get on the serial monitor: 65 65 A AA

Check for ASCII table on the internet and you'll see a list of code for letters representation.

Now: Serial.println("65"); don't print the number 65. It prints the "letters" for human representation of this number. In fact, 65 is a number but here is the "human word".

If you have 65 potatoes in a bag, a french will say "soixante cinq". An Englisman will say "sixty five" and a portuges will say "sesenta y cinquo". But they have all the same number of potatoes.

So the computer has the number but the human has the visual representation of the number.

Serial.print convert automaticly the numerical value in a "letter value". So when you do Serial.print(65) you don't print ONE byte... but TWO! First one is the human representation of 6 (which has the ASCII value of 54) and the the human representation of 5 (which has the ASCII value of 53)

Then the next line also print 65 because I have had "quote". So Serial.print dsplay this as a text.

The third write "A" which is a "text"

Then we use Serial.write(). Serial.write don't try to create a "human" point of view. So it uses directly the number as an ASCII value. As 65 is the ASCII value for A, Serial.write(65) send only ONE byte and show it as the ASCII letters so A. And of course Serial.write('A') give the same result.

For transmission, this is the very first point to understand: if you transmit a byte with value of 65 you'll get this same value on the other side. But depending on the way you display, you can be fooled and believe transmission was wrong ("I send 'A' and receive 65!")

For the second point ("how can I transmit more than a byte"): if you have 2 values to send and each one is on one byte, you have to send two bytes. While receiving, you put the first byte coming in, in a variable, and the second in an other.

If you have to transmit a values using an INT so two bytes, you have to "break" the INT into bytes.

Eg the INT as a value of 3154 (in décimal). Its Hexa representation is 0x0C52. You can break this in two blocks: 0x0C it the value of half of the INT and 0x52 is the other part.

So you can transmit 0x0C (higher part of the INT), then 0x52 (lower part of the INT) and while receiving you use the two bytes to "build again" the INT value.

To send 0x0C52 (INT) and 0xF345AC12 (LONG) you must send: 0x0C, 0x52, 0xF3, 0x45, 0xAC and 0x12 so a total of 6 bytes. Then while receiving you "build back" the value. Of course, if you don't remember the way you "break for sending", you can be confused. Because 0x0C, 0x52, 0xF3, 0x45, 0xAC and 0x12 can be seen as:

  • six bytes
  • three INT (0x0C52, 0xF345 and 0xAC12),
  • one long and two bytes (0x0C52F345, 0xAC and 0x12) etc...

So you must "rebuild" according to the way you "break" the data while sending!

Hope this will help understanding.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.