Arduino Nano boards connected via UART
2 min read

UART Communication Between Two Arduino Boards


UART (Universal Asynchronous Receiver/Transmitter) is one of the simplest and most widely used serial communication protocols in embedded systems. In this project, I connected two Arduino Nano boards to exchange sensor data reliably.

Hardware Setup

Arduino A (TX) → Arduino B (RX)
Arduino A (RX) ← Arduino B (TX)
GND → GND

No level shifting needed — both boards run at 5V logic.

Protocol Design

Raw UART has no notion of message boundaries. I used a simple frame format:

[0xAA] [LEN] [DATA...] [CRC]
  • 0xAA — start byte
  • LEN — payload length
  • DATA — the actual payload
  • CRC — simple XOR checksum

Implementation

#define START_BYTE 0xAA
uint8_t send_frame(uint8_t *data, uint8_t len) {
uint8_t crc = 0;
Serial.write(START_BYTE);
Serial.write(len);
for (uint8_t i = 0; i < len; i++) {
Serial.write(data[i]);
crc ^= data[i];
}
Serial.write(crc);
}

On the receiving end, I implemented a simple state machine:

enum { WAIT_START, WAIT_LEN, WAIT_DATA, WAIT_CRC } state = WAIT_START;
void process_byte(uint8_t b) {
switch (state) {
case WAIT_START:
if (b == START_BYTE) state = WAIT_LEN;
break;
case WAIT_LEN:
expected = b; idx = 0; state = WAIT_DATA;
break;
case WAIT_DATA:
buf[idx++] = b;
if (idx == expected) state = WAIT_CRC;
break;
case WAIT_CRC:
// verify checksum and reset
state = WAIT_START;
break;
}
}

Key Takeaways

  • Always use a frame protocol — raw byte streams are error-prone
  • A CRC or checksum catches corrupted data
  • State machine parsing is robust and simple
  • At 115200 baud, a Nano can handle several thousand frames per second without missing data