Serial communication question, what is going on here?

I wrote two small sender / receiver programs to test very basic serial uno to uno communication that i have pasted below. The program 'sort of' works. Here is what it is supposed to do:

Sender code has variables "value" and "value1". Whenever "value = 0" then "value1 = 1" and vice versa so they are always opposite. Every run of loop() it flips the values.

Receiver has exact same variables defined. Sender sends the values of each variable to Receiver every run of loop().

Receiver turns LED1 ON if "value = 1" and OFF otherwise. It turns LED2 ON if "value1 = 0" and OFF otherwise.

What I expect to see is the two LEDS hooked to the receiver flip-flopping every half-second, when one is ON, the other is OFF, and they keep cycling like that indefinitely.

This works just fine for 38 cycles then suddenly both LED's turn ON at the same time for a half-second, then OFF at the same time for a half-second.


Question 1: Why is this happening?

Question 2: I modified sample code I pulled off the internet. I call Serial.write(value) then immediately call Serial.write(value1) from the sender. Then I called Serial.read() two times immediately after each other in the receiver code. It seems to sync the variables correctly, such that "Serial.write(value)" from sender is being read into "value" on the receiver (same applying to "value1"). Thing is, I don't really understand how the code 'knows' to do this. How does it know to feed the right stream of data into the correct variables without some sort of synchronized timing?

Question 3: I purposely made sure the delay() in the sender and receiver were different to test exactly how this works. The sender is attempting to send data once every 100ms, while the receiver ony receives data every 500ms. I see the "tx" led on the receiver pulsing away at 100ms. What is happening here? Is roughly four out of five transmissions lost because the receiver is not polling for data with Serial.available() at that exact moment? I know I2C acts as an interrupt which makes sense, but with basic tx/rx serial communication do you simply have to poll and then have the receiver board send back a "transmission came through ok" signal to the sender before sending more data?

Here is the code.

SENDER:

//Sender Code

int value = 1; // dictates LED1 status on receiver board
int value1 = 0; // dictates LED2 status on receiver board

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

void loop() {

  Serial.write(value);
  Serial.write(value1);
  
  delay (100);
  
  //flip-flops "value" and "value1" 
  if (value == 1){value = 0;}
  else{value = 1;}
  if (value1 == 1){value1 = 0;}
  else{value1 = 1;}
  //Serial.print(value);
  //Serial.print(value1);
}

RECEIVER:

//Receiver Code

int LED1 = 13;
int LED2 = 7;

int value = 0;
int value1 = 0;

void setup() 
{
  Serial.begin(9600);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
}

void loop() {
  
  if (Serial.available()) 
  {
    value = Serial.read();
    value1= Serial.read();
   }
  
    delay(500);
  
    if (value == 1)
      {digitalWrite(LED1, HIGH);}
    else
      {digitalWrite(LED1, LOW);}
    
    
    if (value1 == 1)
      {digitalWrite(LED2, HIGH);}
    else
      {digitalWrite(LED2, LOW);}
}
  if (Serial.available())
  {
    value = Serial.read();
    value1= Serial.read();
   }

If Serial.available is non-zero it only guarantees you that there is at least one character ready to be read but you read two anyway. Try:

  if (Serial.available() >= 2)

Pete

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data without blocking and without needing delay()s. There is also a parse example.

...R