2

I am trying to transfer unsigned int values between 2 Arduinos. When sending 61805 for the first 8-9 times, I am getting 61805. But after then after these numbers: 61937 28013 61937.

Sender's code:

unsigned int s = 0;

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

void loop()
{
  s = 61805;
  Serial.write(highByte(s)) ;
  Serial.write(lowByte(s));
}

Receiver's code:

unsigned int upperByte, lowerByte, r=0,p=0;

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

void loop () 
{
  if (Serial.available() > 1)
  {
    upperByte = Serial.read();
    lowerByte = Serial.read();
  }

  r = (upperByte << 8) + lowerByte;
  Serial.println(r);
}

2 Answers 2

2

There's no flow control on the Uno and Nano serial and you are sending fast enough that bytes are being dropped, and there's no way your protocol or lack of one demarcates separate messages (separate numbers).

This will become more clear if you write your numbers in hexadecimal:

Dec Hex
61805 0xf16d
61937 0xf1f1
28013 0x6d6d
61937 0xf1f1

Adding a delay between messages can serve to separate the messages if the receiving side makes use of a timeout and can prevent the receiving side from being overwhelmed with data.

If you don't want to use time to slow down and separate your data, you can change what is sent instead. One idea is to have the receiver actively request data when it's ready to receive some. The receiver should expect only entire messages between requests, and if anything gets garbled, it can just read whatever data has come in and throw it out before the next request.

Your messages can also be separated by some characters that aren't part of the messages themselves. A common way to do that is just to encode your numbers as separate text lines, the line terminator \n serving as the separator between messages.

I have not tested these yet, but here are some very minimal modifications to your code that approach having a protocol with fewer of these problems:

Sender:

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

void loop() {
  // await message request
  while(Serial.read() != '.') {
  }

  //
  const unsigned int s = 61805;
  Serial.write(highByte(s)) ;
  Serial.write(lowByte(s));
}

Receiver:

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


void loop () {
  // request message
  Serial.write('.'); 


  // await two-byte response
  const unsigned long request_sent = millis();
  while (Serial.available() < 2 && millis() - request_sent < 1000) {
  }


  if (Serial.available() != 0) {
    if (Serial.available() == 2) {
      // two byte response receive 
      const unsigned upperByte = Serial.read();
      const unsigned lowerByte = Serial.read();
      const unsigned r = (upperByte << 8) + lowerByte;
      Serial.println(r);
    }  else {
      // Something went wrong, too or too few bytes received;
      // throw them out and start over.
      delay(100);
      while (Serial.read() != -1) {}
    }
  }
}

It's a long way from doing it properly, but it should behave at least better than what you started with. There's a lot to designing even simple protocols. Typically there are start and end frame bytes, a checksum or CRC, a message number counter, etc.

2
  • thanks brother it worked .....thanks a lot.... Commented Mar 2, 2021 at 4:19
  • We use to send 8,N,2 and receive on 8,N,1. That gave us an extra bit time to adjust for clock skew.
    – Gil
    Commented Mar 3, 2021 at 21:23
0

This line of the receiver's code:

Serial.println(r);

is transmitting 7 bytes (5 digits, CR and LF). At 9600/8N1, each byte takes 1.04 ms, so the whole message is transmitted in 7.28 ms. In the meantime, the sender is sending 2-byte messages at full speed (no pause between the bytes). The receiver thus gets a new message every 2.08 ms.

So, this receiver is given a new message to relay every 2.08 ms, and it needs 7.28 ms to relay each message. Something has to give...

The reason it works in the beginning is that the receiver has a buffer where it stores the bytes that have been received, and another one for the bytes that have been made ready for transmission. As long as there is room in those buffers, everything works fine. The transmit buffer fill-up first, as it gets 7 bytes to transmit every 2.08 ms. Once it's full, Serial.println() becomes a blocking function: it has to wait for the buffer to have enough room. Your loop() then slows down to match the speed of the transmission, which means you do not read the receive buffer often enough. Then the receive buffer fills up, and you start loosing bytes.

1
  • thanks brother for you effort.... nicely explained... got the point Commented Mar 2, 2021 at 4:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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