In consistent reading with Arduino to Arduino Communication

I have 2 arduino Uno's communicating with each other via HC-05 bluetooth modules. When using my ADXL335 accelerometer the values come out in the 200' range on the master but when the slave prints whats its reading its in the 50's and is inconsistent. The BAUD is 9600 on the devices, the com ports and the IDE

For example if the master reads 266,267,267 from the accelerometer and transmits to the slave, the slave sees it as 50,10,51 or something close to that. I can write a character such as A and the slave picks it up just fine.

Any ideas? See code below

Master 

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

void loop() 
{
  int X = analogRead(A5);
  int Y = analogRead(A4);
  int Z = analogRead(A3);
  Serial.print(X);
  delay(500);
}
Slave

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

void loop() 
{
  if (Serial.available() > 0)
  {
  int X = Serial.read();
  Serial.print("X value:  ");
  Serial.println(X);
  delay(500);
  }
}

(deleted)

Any ideas?

Well, the ASCII code for a '2' is 50 (0x32).

When your master uses Serial.print(X); it actually sends a few characters. For example if X was 1023 it would send 4 characters.

Your slave only reads one character using Serial.read() and, even though you are saving it in an INT it is actually only a byte that is received.

If you use Serial.write(X); in your master I'm not sure what it will send. If it works at all I think it will only send the low 8 bits of the value from the ADC. That would mean all values up to 255 would be sent correctly and values above that would be wrong.

The simplest solution is probably to modify your slave code so it receives as many bytes as are sent. You could get the master to use Serial.println(X) so that the slave could use the extra CR LF characters to detect the end of the transmission.

Some of the code in this demo should give the idea.

...R

Robin2: When your master uses Serial.print(X); it actually sends a few characters. For example if X was 1023 it would send 4 characters.

Your slave only reads one character using Serial.read() and, even though you are saving it in an INT it is actually only a byte that is received.

If you use Serial.write(X); in your master I'm not sure what it will send. If it works at all I think it will only send the low 8 bits of the value from the ADC. That would mean all values up to 255 would be sent correctly and values above that would be wrong.

The simplest solution is probably to modify your slave code so it receives as many bytes as are sent. You could get the master to use Serial.println(X) so that the slave could use the extra CR LF characters to detect the end of the transmission.

Some of the code in this demo should give the idea.

...R

Ok, after looking at your demo I am getting closer. The readSeveralChar() function has really helped but I just need a little bit of clarification. If the master uses Serial.println(X) and X = 266 it will send a total of 5 characters 2 6 1 CR and LF?

I would need to set byte maxChars to 5 and set the terminator to LF. Though I'm not sure what values to use in the if statement below to set the terminator.

if (ndx > maxChars) {  // to make sure the terminator is not written beyond the array
        ndx = maxChars;
      }
      inputSeveral[ndx] = 0; // add a zero terminator to mark the end of the string
    }

I've written a few different demos now and I am getting them mixed up in my mind.

You can't set maxChars to 5 because there will be situations where it may be 4 or 6. Maybe even 3.

You need a different approach in which the code looks for the terminating LF character. The code in Chapter 8 of this (new) demo shows the idea. It is a little simpler than the first demo I linked to.

However your code will have to ignore the last two characters when figuring out the value that has been received. I think you could probably back-up 2 positions when writing the terminating 0.

...R

try this simple (untested) approach:

Master:

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

void loop() 
{
  int X = analogRead(A5);
  int Y = analogRead(A4);
  int Z = analogRead(A3);
  Serial.print('X');
  Serial.println(X);
  Serial.print('Y');
  Serial.println(Y);
  Serial.print('Z');
  Serial.println(Z);
  Serial.println('q');//<<<<<<<< terminator will cause the Serial.parsInt() to not timeout
  delay(500);
}

Slave:

int X;
int Y;
int Z;

//
void setup() 
{
  Serial.begin(9600); 
  Serial.setTimeout(50);// you may need to adjust
}

void loop() 
{
  if (Serial.available())
  {
    char myData = Serial.read();
    if (myData == 'X')
    {
      X = Serial.parseInt();
      Serial.print("X value:  ");
      Serial.println(X);
    }
    else if (myData == 'Y')
    {  
      Y = Serial.parseInt();
      Serial.print("Y value:  ");
      Serial.println(Y);
    }
    else if (myData == 'Z')
    {
      Z = Serial.parseInt();
      Serial.print("Z value:  ");
      Serial.println(Z);
    }
  }
}

Thanks BulldogLowell, that worked right off the bat. I am using a very similar setup for my button control though the slight delay will make the controls kind of clunky.

@Robin 2
I am not sure what you mean by back it up a couple of positions when setting the terminator? Do you mean subtract 2 from ndx? If I don’t set the max chars to 3 I never get the correct number 0 just results in really low numbers the whole time.

See attached images to see how the slave reads it and how the master writes it using the code below.

char X = 'X';
byte inputByte = 255;
const byte buffSize = 32;
char inputSeveral[buffSize];
byte maxChars = 3;
byte bytesRecvd = 0;
const char terminator = '\n';
void setup() 
{
Serial.begin(9600);  // put your setup code here, to run once:

}

void loop() 
{
   // this reads all the characters in the input buffer
      // if there are too many for the inputSeveral array the extra chars will be lost

    inputSeveral[0] = 0; // makes inputSeveral an empty string with just a terminator
    
    byte charCount = 0;  // the number of characters actually received - some may be lost
    byte ndx = 0;        // the index position for storing the character
    
    if (Serial.available() > 0) 
    {
    
      while (Serial.available() > 0) 
      { // keep going until buffer is empty
        if (ndx > maxChars - 1) 
        { // -1 because arrays count from 0
          ndx = maxChars;     // if there are too many chars the extra ones are 
        }                     //   dumped into the last array element which will
                              //   be overwritten by the string terminator
        inputSeveral[ndx] = Serial.read();
        ndx ++;        
        charCount ++;
      }
      
      if (ndx > maxChars) 
      {  // to make sure the terminator is not written beyond the array
        ndx = maxChars;
      }
      inputSeveral[ndx] = terminator; // add a LF terminator to mark the end of the string
    }
    
    Serial.print("Num Chars Rcvd --- ");
    Serial.print(charCount);
    Serial.print("  ---  ");
    Serial.println(inputSeveral);

Master.PNG

I used your 500ms interval for transmission, you can speed that up...

Also, try to reduce the timeout in Serial.setTimeout() to a smaller number, like 15 or even less.

You can also send a trailing char like 'q' and it will read right away, no delay.... code modified above.

Some test code I’ve used on an RX arduino. I added a line to convert captured readString to an integer.

//zoomkat 3-5-12 simple delimited ',' string tx/rx 
//from serial port input (via serial monitor)
//and print result out serial port
//Connect the sending arduino rx pin to the receiving arduino rx pin. 
//Connect the arduino grounds together. 
//What is sent to the tx arduino is received on the rx arduino.
//Open serial monitor on both arduinos to test

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like wer,qwe rty,123 456,hyre kjhg,
  //or like hello world,who are you?,bye!,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.print(readString); //prints string to serial port out to serial monitor
        Serial.println(','); //prints delimiting ","
        //do stuff with the captured readString 
        int n = readString.toInt();  //convert readString into a number
        readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

AgentNoise: @Robin 2 I am not sure what you mean by back it up a couple of positions when setting the terminator? Do you mean subtract 2 from ndx? If I don't set the max chars to 3 I never get the correct number 0 just results in really low numbers the whole time.

The code in the second link I provided doesn't use maxChars at all. It just waits for the end-marker. If you receive 1 2 3 CR LF you need to put a 0 where the CR is.

...R