Introduction: Arduino Serial Link Using Ethernet and UDP Packets

About: Dr James Moxham is a general medical practitioner in Blackwood, Australia. His interests include general family medicine, medical politics, microcontrollers and tending a rose garden. He lives on a property wi…

I needed to send some serial data from one side of the house to the other. Rather than run a cable, why not use the existing home ethernet? This link is bi-directional and uses the UDP packet protocol. I've had these ethernet shields for several years but never been able to get them to work until now (more on this later). ChatGPT helped simplify the code.

Supplies

This project uses two arduino Uno boards, two Arduino ethernet shields and possibly, eight 56ohm resistors.

Step 1: Code

The code is the same on each board. Change one line #define BOARD_NUMBER to either 1 or 2. This swaps the source and destination IP addresses. Also each mac address is different. For testing I had two instances of the arduino IDE open at the same time, and two serial monitors. Type things into one monitor and they are sent to the other.


// serial link using ethernet hardware
// https://www.dreamgreenhouse.com/projects/arduino/tips.php
// incorrect component on the board for the termination resistors
// the one that works has the correct network resistor, labelled 510
// the incorrect one has 511 and most of mine have the incorrect one
// and https://forum.arduino.cc/t/ethernet-sheild-w5100-not-working-with-uno/338884/2
// https://forum.arduino.cc/t/ethernet-sheild-w5100-not-working-with-uno/338884/41
// pictures https://imgur.com/a/JrPFD
// https://reedpaper.wordpress.com/2018/09/17/arduino-ethernet-w5100-how-to-fix-the-wrong-board/
// ip addresses need to be fixed. mDNS can be used as can multicast but this adds a lot more code


#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>


unsigned int localPort = 8888; // Local port to listen on
unsigned int destPort  = 8888; // Destination port
EthernetUDP Udp;


// Define the board number (1 or 2)
#define BOARD_NUMBER 1 // Change this to 1 or 2 depending on the board


// Define IP addresses based on the board number
#if BOARD_NUMBER == 1
  IPAddress     ip(192, 168, 1, 100); // IP address for board number 1
  IPAddress destIP(192, 168, 1, 101); // IP address of board number 2
  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xE1 };
#elif BOARD_NUMBER == 2
  IPAddress     ip(192, 168, 1, 101); // IP address for board number 2
  IPAddress destIP(192, 168, 1, 100); // IP address of board number 1
  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xE2 };
#else
  #error "Invalid BOARD_NUMBER specified"
#endif


#define BUFFER_SIZE 32
char buffer[BUFFER_SIZE];
int head = 0;
int tail = 0;


void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  Udp.begin(localPort);
}


void loop() {
  // Check for data from Serial and send it via UDP
  if (Serial.available()) {
    sendSerialDataViaUDP();
  }
  // Check for data from UDP and send it via Serial
  if (Udp.parsePacket()) {
    receiveUDPDataAndSendViaSerial();
  }
  delay(20); // Wait 20 milliseconds which is 20 characters, udptxpacketsizemax is 24
}


void sendSerialDataViaUDP() {
  while (Serial.available()) {
    buffer[head] = Serial.read();
    head = (head + 1) % BUFFER_SIZE;
  }
  // Check if there is data in the buffer to send
  if (head != tail) {
    // Calculate the number of bytes to send
    int bytesToSend = (head > tail) ? (head - tail) : (BUFFER_SIZE - tail + head);
    // Send the data via UDP
    Udp.beginPacket(destIP, destPort);
    for (int i = 0; i < bytesToSend; i++) {
      Udp.write(buffer[tail]);
      tail = (tail + 1) % BUFFER_SIZE;
    }
    Udp.endPacket();
  }
}


void receiveUDPDataAndSendViaSerial() {
  char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
  int packetSize = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
  for (int i = 0; i < packetSize; i++) {
    Serial.write(packetBuffer[i]);
  }
}



Step 2: Debugging

I have ten of these boards bought over a number of years from different suppliers. Only one actually worked and it took over a day of debugging to find out why. Many boards have the wrong terminating resistors! There is an explanation here https://www.dreamgreenhouse.com/projects/arduino/tips.php and I copied the photos from here https://imgur.com/a/JrPFD The component in question is a four resistor array and the resistors are supposed to be 51 ohms and the correct part will be numbered 510. The incorrect part is numbered 511 which is a network of 510 ohm resistors. The problem is that it will still work if the network cable is short, but over a couple of metres and it becomes unreliable. There are other discussions about setting pin 4 high, and changing the reset capacitor but I found these were not necessary.

For simple debugging, open a cmd window and ping the board.

The chip does run a little warm so I've glued on a small heatsink.

Step 3: Wireless

What if the house is wireless? There are solutions using ESP32 chips. Another simple answer is a an 'access point'. I've got a number of these (TP-Link, multiple models) and they can be configured to convert a wireless to a wired connection.

It is also possible to open up ports in the router (port forwarding) and create serial links using the wider internet.

It is also possible to add more nodes and create a virtual serial network.