Different protocols

(written with the help of ChatGPT)

This page seeks to give you a basic overview om different strategies to connect different hardware components to each other while introducing you to key koncepts around it

If you do not know about bits and bytes read here

Simplex, half duplex, and full duplex are different modes of data transmission in communication systems. 

Asynchronous communication is a method of data transmission in which each data character is sent individually, without any fixed-size frames or blocks. Each character is transmitted with start and stop bits, which allow the receiving device to identify the start and end of each character. Asynchronous communication does not use a common clock signal to synchronize the transmitting and receiving devices.

It often uses one wire for receiving (rx) and one for transmitting (tx). Both ends of communication needs to have the save read and write speed.

Common Asynchronous protocols:

Common synchronous protocols:

Synchronous communication is a method of data transmission in which data is sent in a continuous stream, with the transmitting and receiving devices synchronized by a common clock signal. The data is transmitted in fixed-size blocks or frames, with each block or frame being transmitted in a single transmission. The receiver waits for the entire block or frame to arrive before processing it, and uses the clock signal to synchronize the transmission and reception of data.

It often uses three wires. One for the clock, one for data and then a Valid or Enable signal. The clock defines the writing speed.

Balanced vs unbalanced signals

In electrical and electronic systems, a signal can be transmitted as either a balanced or an unbalanced signal.

An unbalanced signal is transmitted over two wires: a signal wire and a ground wire. The signal wire carries the actual signal, while the ground wire serves as a reference point for the signal. Unbalanced signals are susceptible to noise and interference, which can cause distortion in the signal.

Example of a balanced signal. It consists of one wire that is either high or low (e.g. 0 or 5v).

Common unbalanced signals:

Common balanced signals:

In contrast, a balanced signal is transmitted over two signal wires that carry equal but opposite signals, and a ground wire. The equal but opposite signals are referred to as a differential signal, and they cancel out any noise or interference that is picked up along the way. As a result, balanced signals are less susceptible to noise and interference, and can transmit over longer distances without losing signal quality.

The principle of a balanced signal is based on the concept of common-mode rejection ratio (CMRR), which measures the ability of a system to reject noise and interference that is present on both signal wires. A high CMRR indicates a strong ability to reject noise and interference, and thus a higher quality signal.

Balanced signals are commonly used in audio and video systems, and in data communication systems, where the quality of the signal is critical to the performance of the system. Unbalanced signals, on the other hand, are often used in simpler systems where the quality of the signal is less important, such as in guitar or microphone cables.

Example of a balanced signal. It consists of two wires that are inverted to each other

Morse code 

Besides smoke signals this is probably one of the most basic protocols.

Morse code is a method of transmitting information using a series of dots, dashes, and spaces.  Although it has largely been replaced by more advanced communication technologies, Morse code remains an important part of radio communication and is still used by some enthusiasts and emergency services.

It was invented by Samuel Morse in the early 19th century and was originally used for telegraph communication. Each letter and number is represented by a unique sequence of dots and dashes, which can be easily transmitted using a simple signaling device such as a telegraph key or flashlight. Morse code has been used in a variety of settings, including aviation, maritime communication, and amateur radio. 

The serial port (RX and TX) are located in pin 0 and 1. Those are the pins that communicated with the  computer.

Serial communication

The serial monitor uses serial to communicate with the computer. This is how you upload new code to the board and it can be used as text output/input. This is useful if you want to know what is going on in your code. You can then send a message back to your computer informing you about something.  A simple example:

void setup()



Serial.println("Hello World");


The above code will start the monitor with a communication speed of 9600 (notice how the monitor window has the same speed - important). Then it will send a message saying, "Hello World". This will inform you that your board has started.

ESP32/Arduino Serial to p5js (Directly)

On some browsers (tested in chrome) you can communicate directly with an Arduino (Any  including ESP32 and UNO) through Serial communication. This example show you how.

Read more here

[show the code]

let serialAvaliable = false;

let serialInput = "";

function setup() {

  createCanvas(400, 400);

  print("press c to connect")


function keyPressed() {

  if (key == "c") {




var timer = 0;

function draw() {


  // prints the serial input buffer when the serialAvaliable flag is true

  if (serialAvaliable) {

    serialAvaliable = false;


    serialInput = "";



  //Send a hello to the arduino every 3 seconds 

  //- if it shows up in the console it means that the arduino returned it

  if (millis() - timer > 3000) {

    timer = millis();

    serialWrite("hello from p5");






let port;

let reader;

let inputDone;

let outputDone;

let inputStream;

let outputStream;

let portIsOpen = false;

async function serialListen() {

  if (portIsOpen) {

    while (true) {

      const { value, done } = await reader.read();

      if (value) {

        serialAvaliable = true;

        serialInput = serialInput + value;


      if (done) {

        console.log("[readLoop] DONE", done);







async function serialConnect() {

  if (navigator.serial) {

    port = await navigator.serial.requestPort();

    await port.open({ baudRate: 9600 });

    const decoder = new TextDecoderStream();

    inputStream = decoder.readable;

    inputDone = port.readable.pipeTo(decoder.writable);

    reader = inputStream.getReader();

    const encoder = new TextEncoderStream();

    outputDone = encoder.readable.pipeTo(port.writable);

    outputStream = encoder.writable;

    portIsOpen = true;

    print("Port is open");


  } else {

    print("Serial not compatible with the browser you are using :/");



function serialWrite(line) {

  if (portIsOpen) {

    // CODELAB: Write to output stream

    const writer = outputStream.getWriter();





[show the arduino code]

void setup() {

  // put your setup code here, to run once:


  while (!Serial) {

    ; // wait for serial port to connect. Needed for native USB port only



unsigned long timer = 0;

void loop() {

  // put your main code here, to run repeatedly:

  if (millis() - timer > 1000)


    timer = millis();



  while (Serial.available() > 0) {




Midi protocol

MIDI (Musical Instrument Digital Interface) is a protocol used for communication between electronic musical instruments, computers, and other devices. It was first introduced in 1983 as a standard for the transfer of musical data, such as note and timing information, between devices. MIDI uses a serial data transmission format, where each message consists of a status byte and one or two data bytes. MIDI messages can be sent and received in real-time, allowing for live performance and recording. MIDI supports a wide range of musical instruments and equipment, including synthesizers, drum machines, and digital audio workstations.

MIDI messages consist of three parts: a status byte, a data byte, and a running status.

The status byte indicates the type of message being sent, such as a note-on or note-off command. The data byte contains additional information about the message, such as the MIDI note number or velocity. The running status is an optimization technique that allows multiple messages of the same type to be sent with fewer bytes by omitting the status byte for subsequent messages.

MIDI messages are transmitted using a 5-pin DIN connector, which carries both the MIDI in and MIDI out signals. The MIDI protocol operates at a speed of 31,250 bits per second (baud rate) and uses a current loop signaling system.

MIDI supports up to 16 channels, allowing multiple instruments to be controlled independently on the same MIDI connection. Each channel can transmit 128 different notes, and messages can also include information about pitch bend, modulation, and other musical parameters.

Read more here and here


void setup() {

  // Set MIDI baud rate:



void loop() {

  // play notes from F#-0 (0x1E) to F#-5 (0x5A):

  for (int note = 0x1E; note < 0x5A; note++) {

    //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):

    noteOn(0x90, note, 0x45);


    //Note on channel 1 (0x90), some note value (note), silent velocity (0x00):

    noteOn(0x90, note, 0x00);




// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that

// data values are less than 127:

void noteOn(int cmd, int pitch, int velocity) {





WS2812B protocol (Neopixels)

The WS2812B protocol is a simple serial communication protocol used for controlling individual or arrays of WS2812B RGB LEDs. The protocol consists of a single data line that is used to transmit a series of 24-bit packets, with each packet corresponding to the RGB values of an individual LED. The data is sent in a specific timing sequence, with a 50 microsecond reset pulse followed by a series of pulses representing each bit of the data. The WS2812B protocol supports daisy-chaining of multiple LEDs, with the data for each LED passed on to the next LED in the chain. The protocol is widely supported by a variety of microcontrollers and other digital devices, making it easy to control WS2812B LEDs using a wide range of hardware and software platforms.

Read more here

RS-485: Balanced serial communication

RS-485 is a communication protocol used for serial communication between devices over long distances.  RS-485 defines the electrical and mechanical characteristics of the communication signals, including voltage levels, signal timing, and connector pinouts. It uses a differential signaling system, which enables data transmission over distances of up to 1200 meters at data rates of up to 10 Mbps. RS-485 is commonly used in industrial automation, building automation, and other applications that require reliable communication over long distances with multiple devices connected to the same communication line.

RS-485 is a balanced communication protocol, which means that it uses a pair of wires to transmit data in a balanced fashion. In a balanced system, each wire carries the same signal with opposite polarities, which helps to cancel out noise and interference that may be present in the transmission line.

In RS-485, the two wires are known as "A" and "B". The voltage level of the "A" wire is inverted and transmitted on the "B" wire, while the voltage level of the "B" wire is inverted and transmitted on the "A" wire. This differential signaling technique allows the receiving device to distinguish between the signal and any noise or interference that may be present in the transmission line.

Additionally, RS-485 uses termination resistors at each end of the communication line to help eliminate reflections that may occur due to signal bounce. The termination resistors ensure that the signal is properly terminated at both ends of the line, which helps to maintain signal integrity and reduce errors.


DMX (Digital Multiplex)

DMX (Digital Multiplex) protocol is a unidirectional, serial protocol based on RS-485. It used in the entertainment industry to control lighting and other stage equipment. It consists of a single data channel that can transmit up to 512 different values, each with a range of 0 to 255. DMX devices are daisy-chained together in a series, with the output of one device connected to the input of the next. The first device is usually the controller, which sends out DMX data packets, and the last device terminates the signal. DMX is popular due to its simplicity, flexibility, and ability to control a wide variety of devices.

Read more here

The Arduino DMX shield - is the simplest way to get dmx up and running. 


Diagram of using a MAX481 chip to send DXM. The MAX chip makes it a balanced signal.

Based on the DMX protocol the ArtNet protocol was developed for ethernet

Art-Net is a protocol used for transmitting DMX512 (Digital Multiplex) data over Ethernet networks. It was developed by Artistic Licence in 2001 as a way to address the limitations of DMX, which was originally designed for point-to-point communication between lighting controllers and fixtures. Art-Net enables DMX data to be transmitted over Ethernet networks, allowing lighting designers to control large numbers of fixtures from a single control point. Art-Net supports up to 32768 universes (each with 512 channels), and devices can be daisy-chained together in a network topology. Art-Net has become a popular protocol in the entertainment industry due to its flexibility, scalability, and ease of use.

Based on the MIDI the open sound control protocol was developed for ethernet

OSC (Open Sound Control) is a protocol used for communication between computers, musical instruments, and other multimedia devices. It was developed in 1997 as an alternative to MIDI, providing a more flexible and extensible framework for transmitting digital signals. OSC messages consist of an address pattern and zero or more arguments, which can include numbers, strings, and binary data.

OSC supports a wide range of applications, including music composition, live performance, and interactive installations. It enables real-time communication between devices and allows for the creation of complex multimedia systems. OSC messages can be sent over a variety of network protocols, including Ethernet, Wi-Fi, and Bluetooth, and can be transmitted over long distances with minimal latency. OSC has become an essential tool for multimedia artists and musicians, providing a powerful and versatile framework for creative expression.

Multiple libraries for ESP32/Arduino exist. E.g. https://github.com/thomasfredericks/MicroOsc 

OSC (Open Sound Control) messages consist of an address pattern and zero or more arguments, which can include numbers, strings, and binary data. The address pattern is a string that specifies the destination of the message and can include wildcards and hierarchical structures to allow for flexible routing of messages. The arguments can be used to transmit a wide range of data, including control messages for music and multimedia applications, sensor data, and network messages.

OSC messages are designed to be extensible, allowing for the creation of custom messages and addressing schemes to support a variety of applications. Messages can be transmitted in real-time, with low latency and high precision, making OSC ideal for interactive multimedia applications. OSC has become an essential tool for multimedia artists and musicians, enabling the creation of complex systems and providing a powerful and flexible framework for creative expression.

The I2C protocol for peripherals with Arduino

I2C (Inter-Integrated Circuit) is a two-wire communication protocol used for connecting microcontrollers and other devices in embedded systems. It consists of a master device that initiates communication and one or more slave devices that respond to commands. The protocol uses a synchronous serial communication format with a clock signal generated by the master device. Data is transmitted in 8-bit packets, and each packet is acknowledged by the receiving device.

I2C supports a wide range of devices, including sensors, memory, and other peripherals, and is widely used in consumer electronics, industrial automation, and automotive applications. The protocol operates at speeds up to 3.4 Mbps and can support multiple devices on the same bus using unique addresses. I2C is a simple, low-cost, and versatile protocol that has become an essential tool for embedded system developers.

Read more here

Shift registers

Shift registers are digital circuits that are used to convert serial data into parallel data or vice versa. They consist of a chain of flip-flops connected in a series, with each flip-flop storing a single bit of data. The data is shifted through the chain of flip-flops in response to clock pulses, allowing for the conversion of serial data into parallel data.

Shift registers are widely used in a variety of applications, including LED displays, data storage, and serial communication interfaces. They can be cascaded together to increase the number of bits that can be stored or to create larger parallel data buses. Shift registers are available in a variety of configurations, including parallel-in, serial-out (PISO), serial-in, parallel-out (SIPO), and universal shift registers that support both serial and parallel data transfer.

Read more here

Illustration from: https://www.youtube.com/watch?v=bqfPZXEuyuc&ab_channel=EEEnthusiast

//Pin connected to ST_CP of 74HC595

int latchPin = 8;

//Pin connected to SH_CP of 74HC595

int clockPin = 12;

////Pin connected to DS of 74HC595

int dataPin = 11;

void setup() {

//set pins to output so you can control the shift register

pinMode(latchPin, OUTPUT);

pinMode(clockPin, OUTPUT);

pinMode(dataPin, OUTPUT);


void loop() {

// count from 0 to 255 and display the number

// on the LEDs

for (int numberToDisplay = 0; numberToDisplay < 256; numberToDisplay++) {

// take the latchPin low so

// the LEDs don't change while you're sending in bits:

digitalWrite(latchPin, LOW);

// shift out the bits:

shiftOut(dataPin, clockPin, MSBFIRST, numberToDisplay);

//take the latch pin high so the LEDs will light up:

digitalWrite(latchPin, HIGH);

// pause before next value:





PS/2 Protocol (Mouse  & Keyboard)

The PS/2 protocol is a synchronous serial communication standard used for connecting keyboards and mice to computers. The interface consists of a 5-pin DIN connector, with two wires dedicated for bi-directional data transmission, one wire for clock signal, and two more wires for power and ground. The protocol operates at a 10-16.7 kHz signal frequency, sending 8-bit packets of data with the first bit indicating if the transmission is from the keyboard or mouse, and the remaining 7 bits containing the actual data. The protocol uses parity checking to detect errors in data transmission, with additional measures to ensure reliable communication including keyboard and mouse reset commands, transmission rate negotiation, and response timeout limits. Overall, the PS/2 protocol is a robust and widely used interface for input devices on legacy computer systems.


#include "PS2Mouse.h"

#define DATA_PIN 5

#define CLOCK_PIN 6

PS2Mouse mouse(CLOCK_PIN, DATA_PIN);

void setup() {




void loop() {

    MouseData data = mouse.readData();

    Serial.print(data.status, BIN);











Infrared (IR) 

Infrared (IR) communication is a wireless technology that uses infrared light to transmit data between devices. IR communication relies on the fact that infrared radiation is emitted by all objects with a temperature above absolute zero. In IR communication, data is typically encoded using on-off keying (OOK) modulation and sent as a series of pulses of light, with the timing of the pulses conveying the information. IR communication is commonly used in remote controls for TVs, DVD players, and other home appliances. However, it has some limitations, such as the need for a clear line of sight between the transmitting and receiving devices, and susceptibility to interference from other light sources.

See Arduino example here

Ir signal from a tv remote can be seen with some cameras.

Network protocols

The amount of network protocols is too wast to uncove here, but a few select examples are relevant to show.

A lot of examples can be found here

Some common network protocols:

IP (Internet Protocol)

TCP/IP (Transmission Control Protocol/Internet Protocol)

UDP (User Datagram Protocol)

DNS (Domain Name System)

DHCP (Dynamic Host Configuration Protocol)

HTTP(S) (Hypertext Transfer Protocol)

FTP (File Transfer Protocol)

SMTP (Simple Mail Transfer Protocol)

NTP (Network Time Protocol)

SIP (Session Initiation Protocol)

RTP (Real-time Transport Protocol)

DHCP (Dynamic Host Configuration Protocol)


WEBRTC (Web Realtime Communication)


[show the arduino code]

// Load Wi-Fi library

#include <WiFi.h>

#include <WebSocketsServer.h>

WebSocketsServer webSocket = WebSocketsServer(81);

// Replace with your network credentials

const char* ssid = "REPLACE_WITH_YOUR_SSID";

const char* password = "REPLACE_WITH_YOUR_PASSWORD";

void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {

  const uint8_t* src = (const uint8_t*) mem;

  Serial.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);

  for (uint32_t i = 0; i < len; i++) {

    if (i % cols == 0) {

      Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);


    Serial.printf("%02X ", *src);





void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {

    switch(type) {

        case WStype_DISCONNECTED:

            Serial.printf("[%u] Disconnected!\n", num);


        case WStype_CONNECTED:


                IPAddress ip = webSocket.remoteIP(num);

                Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);

        // send message to client

        webSocket.sendTXT(num, "Connected");



        case WStype_TEXT:

            Serial.printf("[%u] get Text: %s\n", num, payload);

            // send message to client

            // webSocket.sendTXT(num, "message here");

            // send data to all connected clients

            // webSocket.broadcastTXT("message here");


        case WStype_BIN:

            Serial.printf("[%u] get binary length: %u\n", num, length);

            hexdump(payload, length);

            // send message to client

            // webSocket.sendBIN(num, payload, length);


    case WStype_ERROR:      



    case WStype_FRAGMENT:

    case WStype_FRAGMENT_FIN:




void setup() {


  // Connect to Wi-Fi network with SSID and password

  Serial.print("Connecting to ");


  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {




  // Print local IP address


  Serial.println("WiFi connected.");

  Serial.println("IP address: ");


  // server address, port and URL


  // event handler



unsigned long timer = 0;

int counter = 0;

void loop() {


  if (millis() - timer > 2000) // send a counter value every 2 sec.


    String numberString = String(counter);


    counter = counter + 1;

    timer = millis();



[show the p5js code]

// where the serial server is (your local machine):

var host = '';

var socket; // the websocket

var sensorValue = 0; // the sensor value

function setup() {

  createCanvas(400, 400);

  // connect to server:

  socket = new WebSocket('ws://' + host);

  // socket connection listener:

  socket.onopen = sendIntro;

  // socket message listener:

  socket.onmessage = readMessage;


function draw() {



  ellipse(sensorValue, height / 2, 20, 20);

  text(sensorValue, 20, 20);


function sendIntro() {

  // convert the message object to a string and send it:



function readMessage(event) {

  var msg = event.data; // read data from the onmessage event

  sensorValue = Number(msg);

  println(sensorValue); // print it


2. Install the library "websocket" by Markus Sattler

3. Copy the Arduino code from above in the collapsable dropdown  to Arduino and change the wifi name and pasword.

4. In the serial terminal see that it connects to your wifi hotspot and take note of the ip number.

5. Open this p5.js sketch and change the ip to the one in your terminal. Press play.

NOTE!! THERE IS A BUG IN THIS EXAMPLE - YOU NEED TO DOWNLOAD THE file in the p5js editor and run it locally - p5js editor defaults to https and  the boards  uses an insecure connection.

Note: use ArduinoWebsockets.h library instead for ssh: https://github.com/gilmaimon/ArduinoWebsockets


[show the arduino code]

// This example uses an ESP32 Development Board

// to connect to shiftr.io.


// You can check on your device after a successful

// connection here: https://www.shiftr.io/try.


// by Joël Gähwiler

// https://github.com/256dpi/arduino-mqtt

#define ONBOARD_LED  2

#include <WiFi.h>

#include <MQTT.h>

WiFiClient net;

MQTTClient client;

unsigned long lastMillis = 0;

void connect() {

  Serial.print("checking wifi...");

  while (WiFi.status() != WL_CONNECTED) {





  while (!client.connect("arduino", "public", "public")) {






  // client.unsubscribe("/hello");


void messageReceived(String &topic, String &payload) {

  Serial.println("incoming: " + topic + " - " + payload);

  if(topic.equals("/idsp5js") && payload.equals("on"))




  else if(topic.equals("/idsp5js") && payload.equals("off"))




  // Note: Do not use the client in the callback to publish, subscribe or

  // unsubscribe as it may cause deadlocks when other things arrive while

  // sending and receiving acknowledgments. Instead, change a global variable,

  // or push to a queue and handle it in the loop after calling `client.loop()`.


void setup() {


  WiFi.begin("WIFINAME", "PASSWORD");

  // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported

  // by Arduino. You need to set the IP address directly.

  client.begin("public.cloud.shiftr.io", net);






void loop() {


  delay(10);  // <- fixes some issues with WiFi stability

  if (!client.connected()) {



  // publish a message roughly every second.

  if (millis() - lastMillis > 1000) {

    lastMillis = millis();

    client.publish("/idsesp32", "I am online");



[show the p5js code]

// Make sure that this string is in your index.html header:

// <script crossorigin="anonymous" src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>


var client;

function setup() {

  createCanvas(windowWidth, windowHeight);

 client = mqtt.connect(



      clientId: "p5jsids",




  client.on("connect", function () {




  client.on("message", function (topic, message) {

     print(topic + ": " + message);




var lightIsOn = false

var mouseIsPressedOld = false

function draw() {


  if(mouseIsPressed == true && mouseIsPressedOld == false)


    lightIsOn = !lightIsOn;



     client.publish("/idsp5js", "on");




     client.publish("/idsp5js", "off"); 



  mouseIsPressedOld = mouseIsPressed;










  text("Click to turn on led",100,100);


function keyPressed()



0. Either setup a wifi connection on your phone or use an existing one. - make sure to have 2.4ghz and maximize compability

1. Install mgtt by Joël Gähwiler for arduino

2. Copy the Arduino code from above in the collapsable dropdown  to Arduino and change the wifi name and pasword.

3. Verify that you are connected in the serial monitor

4. Load up the p5js sketch:  https://editor.p5js.org/hobye/sketches/Wdui-3T2U

and click the canvas to turn on and off the blue led on the board