Arduino serial communication

One or more serial ports (UART or USART) are available on each Arduino board (depending on the type). The serial port provides communication between the Arduino board and suitable devices.

Note that serial communication on the Arduino board uses TTL logic levels on the TX/RX pins, which can be 5V or 3.3V depending on the board. If the device you want to connect works with the same voltage, you can connect them directly to each other. In the picture below, the Arduino UNO is connected to an HC-05 Bluetooth module. Since both circuit boards operate at 5V voltage, we can connect them directly.

Arduino serial port connection

If the voltage of the devices is not the same, then a level matching circuit must be used. Failure to do so may damage the Arduino board or the connected device. The following figure shows the serial connection of the Arduino UNO and an ESP8266-01 module. The two circuit boards operate at different voltages, this problem is solved by the level matching circuit.

Arduino serial port connection with level matching circuit

Arduino Uno, Nano and Mega boards have a USB-Serial converter, they use pins 0 and 1 to communicate with the computer.

Arduino Mini boards do not have a USB-Serial gateway on board, so we need such a device to communicate with the computer. Connect the TX pin of the Arduino board to the RX pin of the USB-Serial converter, then the Arduino RX to the TX pin of the USB-Serial converter, and finally connect the GND pins.

Arduino mini pro - FTDI232 with USB-Serial gateway

The Arduino Mega has a total of 4 serial ports. The first serial port is connected to the on-board USB-Serial converter. To use the extra serial ports to communicate with your computer, you will need an additional USB-to-serial adapter.

In the table below you can see on which pins the serial port is located on some Arduino boards.

Arduino BoardsSerialSerial1Serial2Serial3
One, Nano, Mini0(RX), 1(TX)
Mega0(RX), 1(TX)19(RX), 18(TX)17(RX), 16(TX)15(RX), 14(TX)
Leonardo, Micro, Yun0(RX), 1(TX)
One WiFi Rev.2Connected to USB0(RX), 1(TX)Connected to NINA
MKR boards13(RX), 14(TX)
ZeroConnected to the Programming Port0(RX), 1(TX)
Due0(RX), 1(TX)19(RX), 18(TX)17(RX), 16(TX)15(RX), 14(TX)
1010(RX), 1(TX)
Serial port pin assignment of Arduino boards

For the Uno, Nano, Mini and Mega, pins 0 and 1 are used to communicate with the computer. These pins can be used as digital outputs and inputs if the serial port is not needed. If we connect something to these pins and want to use the serial port, it can disrupt communication and cause unsuccessful program uploads to the Arduino board.

You may need these for practice:

advertising – Amazon.com

Serial communication, the software part

Let’s see how we can get the serial communication working on the Arduino board. No extra library is needed to use serial communication, the Arduino IDE contains the necessary functions.

The first most important function is the Serial.begin(baud); sets the data rate for serial data transfer. The baud value must be specified in bits per second. This must be specified in the setup() function.

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

void loop()
{
  
}

To communicate with the Arduino IDE Serial Monitor, select one of the baud rates in the drop-down menu in the lower right corner of the screen.

​​Arduino Serial Monitor baud rate setting
​​Arduino Serial Monitor baud rate setting

Serial.begin(baud, config); The optional second argument configures the data, parity, and stop bits. The default is 8 data bits, no parity, and a stop bit.

void setup()
{
  Serial.begin(9600, SERIAL_8N1);   // default
}

void loop()
{
  
}

Choose from the following valid values:

No parity:

SERIAL_5N1
SERIAL_6N1
SERIAL_7N1
SERIAL_8N1
SERIAL_5N2
SERIAL_6N2
SERIAL_7N2
SERIAL_8N2

Even Parity:

SERIAL_5E1
SERIAL_6E1
SERIAL_7E1
SERIAL_8E1
SERIAL_5E2
SERIAL_6E2
SERIAL_7E2
SERIAL_8E2

Odd Parity:

SERIAL_5O1
SERIAL_6O1
SERIAL_7O1
SERIAL_8O1
SERIAL_5O2
SERIAL_6O2
SERIAL_7O2
SERIAL_8O2

Back to table of contents.

The Serial.end() function disables serial communication, freeing up the RX and TX pins so they can be used as outputs and inputs. If we want to use serial communication again, we have to call the function Serial.begin() .

Let’s try it:

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

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

void loop() 
{
  Serial.println("1. String");
  Serial.end();

  pinMode(0, OUTPUT);
  digitalWrite(0, HIGH);
  delay(500);
  digitalWrite(0, LOW);

  Serial.begin(9600);
  Serial.println("2. String");
  delay(1000);
}

Back to table of contents.

Serial.flush() waits for outgoing serial data to complete. In most cases, a serial transfer buffer is a good thing, it prevents the Arduino program from being tied up waiting for a serial transfer. But it may happen that you have to wait for the end of the serial data transfer in the Arduino program. The Serial.flush() function helps with this.

Serial.println(F("Hi Arduino!"));
Serial.flush();

Back to table of contents.

if(Serial) returns true if the specified serial port is ready for use . This is important when using cards with native USB. For non-USB CDC ports, this will always be true.

void setup()
{
  Serial.begin(9600);
  while(!Serial)
  {
    // Waits for the serial port to connect. 
    // Required for cards with native USB!
  }
}

void loop()
{
  
}

Back to table of contents.

Serial.print() prints the data as ASCII text to the serial port.

Numbers use ASCII characters for each digit.

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

void loop()
{
  Serial.print(29);  // 29
  delay(1000);
}

The second parameter, which can be added optionally, defines the format, in the following code snippet, for example, we can print the value in different number systems.

Serial.print(29, BIN);  // 11101

Serial.print(29, OCT);  // 35

Serial.print(29, DEC);  // 29

Serial.print(29, HEX);  // 1D

Floating-point numbers are printed to two decimal places by default.

Serial.print(1.23456);  // 1,23

The optional second parameter specifies the number of decimal places to use for floating-point numbers.

Serial.print(1.23456, 0);  // 1

Serial.print(1.23456, 1);  // 1,2

Serial.print(1.23456, 4);  // 1,2345

Bytes are sent as a single character.

Characters and strings are sent as is.

Serial.print('M');                 // M
Serial.print("myhomethings.eu")    // myhomethings.eu

Back to table of contents.

Serial.println() works similarly to Serial.print() , except that Serial.println() returns a carriage return character (ASCII 13 or ‘\r’) and a newline character (ASCII 10 or ‘\ n’) is supplemented.

Back to table of contents.

The Serial.write() writes binary data to the serial port. The data is sent as a byte or sequence of bytes. To send numeric characters, use the Serial.print() or Serial.println() function.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

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

void loop() 
{
  Serial.write(65);     // ASCII 65 -> A
  Serial.write(66);     // B
  Serial.write(67);     // C
  Serial.write('\n');   // newline character


  int bytesLength = Serial.write("myhomethings.eu\n");  
  // Prints the String "myhomethings.eu" and returns the length of the String
  
  Serial.println(bytesLength);
  // To send numeric characters, use the print() or println() function.
  
  char buf[] = {'m','y','h','o','m','e','t','h','i','n','g','s','.','e','u','\n'};
  int len = 16;

  Serial.write(buf, len);   // Sends "len" number of bytes from the buf array

  Serial.write('\n');
  delay(1000);
}

Back to table of contents.

Serial.availableForWrite() is used to get the number of bytes that can be written to the serial buffer without blocking the write operation. Let’s see an example of its use.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

String myString = "Arduino serial buffer - myhomethings.eu";

void setup() 
{
  Serial.begin(9600);
  
  // we query the size of the buffer and then write it to the serial port.
  Serial.print("TX buffer size: ");
  Serial.println(Serial.availableForWrite());
}

void loop() 
{
  // if the buffer size is larger than String...
  if(Serial.availableForWrite() > myString.length()) 
  {

    // we write the String to the serial port
    Serial.println(myString);
  }
  delay(1000);
}

Back to table of contents.

Serial.available() returns the number of bytes read from the serial port that are already stored in the serial receive buffer. In the example below, we check if the receive buffer contains data. If the receive buffer is not empty, the Serial.read() function is used to read until it is empty.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

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

void loop()
{
  if(Serial.available() > 0)
  {
    char myChar = Serial.read();
    Serial.print(myChar);
  }
}

Back to table of contents.

Serial.read() reads data from the serial port. Its return value is the first byte of incoming serial data, or -1 if there is no further data in the serial receive buffer.

Back to table of contents.

Serial.readBytes() reads characters from the serial port into a buffer. The function terminates when the specified length has been read, or when the default timeout of 1 second or the value specified in Serial.setTimeout() is exceeded . Serial.readBytes() returns the number of characters in the buffer, or 0 if no valid data is found.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char myBuff[64];
int len = sizeof(myBuff)-1;

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

void loop()
{
  if(Serial.available() > 0) 
  {
    size_t read = Serial.readBytes(myBuff, len);
    myBuff[read] = '
/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/
char myBuff[64];
int len = sizeof(myBuff)-1;
void setup()
{
Serial.begin(9600);
}
void loop()
{
if(Serial.available() > 0) 
{
size_t read = Serial.readBytes(myBuff, len);
myBuff[read] = '\0';
Serial.print(myBuff);
}
}
'; Serial.print(myBuff); } }

Back to table of contents.

Serial.readBytesUntil() reads characters from the serial buffer into an array. The function ends when the specified length has been read, when there is a timeout, or when the terminating character is found.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char myBuff[64];
int len = sizeof(myBuff)-1;

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

void loop()
{
  if(Serial.available() > 0) 
  {
    size_t read = Serial.readBytesUntil('\n', myBuff, len);
    myBuff[read] = '
/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/
char myBuff[64];
int len = sizeof(myBuff)-1;
void setup()
{
Serial.begin(9600);
}
void loop()
{
if(Serial.available() > 0) 
{
size_t read = Serial.readBytesUntil('\n', myBuff, len);
myBuff[read] = '\0';
Serial.println(myBuff);
}
}
'; Serial.println(myBuff); } }

Back to table of contents.

Serial.readString() reads characters from the serial buffer into a String. In the event of a timeout, the function stops, if necessary, this time can be set with the Serial.setTimeout() function. The Serial.readString() function does not stop if the data contains end-of-line characters. 

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

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

void loop()
{
  Serial.println("The text please:");
  if(Serial.available() > 0) 
  {
    String myString = Serial.readString();
    myString.trim();
    if(myString != "")
    {
      Serial.print("The entered text: ");
      Serial.println(myString);
      myString ="";
      Serial.println("The text please:");
    }
  }
}

Back to table of contents.

The Serial.readStringUntil() function reads the characters from the serial buffer up to the terminating character into a String. The terminating character is not included in the String. The function stops in case of timeout. The time can be postponed using the setTimeout() function.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char terminator = 't'; // the closing character

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

void loop()
{
  Serial.println("The text please:");
  if(Serial.available() > 0) 
  {
    String myString = Serial.readStringUntil(terminator);
    myString.trim();
    if(myString != "")
    {
      Serial.print("The entered text: ");
      Serial.println(myString);
      myString ="";
      Serial.println("The text please:");
    }
  }
}

Back to table of contents.

Serial.find() reads data from the serial buffer until it finds the target parameter or reaches the end or times out. The time can be set with the setTimeout() function. The function returns true if the target is found, false if not.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char target[] ="hello";

void setup()
{
  Serial.begin(9600);
  Serial.println("The text please:");
}

void loop()
{

  if(Serial.available() > 0) 
  {
    if (Serial.find(target))
    {
      Serial.println("Found it!");
    }
    else
    { 
      Serial.println("Unfortunately, it was not found!"); 
    }
    Serial.println("The text please:");
  }
}

Optionally, a second length parameter can be specified, which defines how many characters to search from the target .

char target[] ="hello";
size_t length = 3;

Serial.find(target, length)

Back to table of contents.

Serial.findUntil() reads data from the serial buffer until it finds the ‘ target ‘ parameter or the terminating string ‘ terminal ‘ or times out. The time can be set with the setTimeout() function. The function returns true if the target is found, false if not.

char target[] ="hello";
char terminal[] = "abc";

Serial.findUntil(target, terminal);

Back to table of contents.

Serial.parseInt() looks for the next valid integer in the incoming serial. The function stops in case of timeout. We can help with this with the setTimeout() function.

If Serial.parseInt() finds non-numeric values ​​before a valid integer, it discards them and returns the integer, leaving the rest. If Serial.parseInt() does not find a numeric value, it returns null.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

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

void loop()
{
  if(Serial.available() > 0) 
  {
    long myInt = Serial.parseInt();
    Serial.println(myInt);
  }
}

The Serial.parseInt() function can also be called with optional parameters.

Serial.parseInt()
Serial.parseInt(lookahead)
Serial.parseInt(lookahead, ignore)

The first optional parameter is lookahead , called lookahead mode. It can have three predefined values.

SKIP_ALL: all characters except digits and the minus sign are ignored when searching for an integer in the data stream. This is the default mode.

SKIP_NONE: Nothing is skipped. If the first value of the serial receive buffer is not a digit, it returns 0.

SKIP_WHITESPACE: Only tabs, spaces, line feeds and carriage return characters are skipped.

The second optional parameter is ignore : the indicated character is skipped in the search. This can be useful if there are known characters that we don’t want to use as delimiters in numbers. It can be used, among other things, to omit decimal points or slashes.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

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

void loop()
{
  if(Serial.available() > 0) 
  {
    unsigned long myInt = Serial.parseInt(SKIP_NONE, ',');
    Serial.println(myInt);
  }
}

Back to table of contents.

Serial.parseFloat() returns the first valid floating-point number from the serial buffer. The first non-floating-point character terminates the Serial.parseFloat() function. The function also stops in the event of a timeout. We can help with this with the setTimeout() function.

The Serial.parseFloat() function can also be called with optional parameters.

Serial.parseFloat()
Serial.parseFloat(lookahead)
Serial.parseFloat(lookahead, ignore)

The first optional parameter is lookahead , called lookahead mode. It can have three predefined values.

SKIP_ALL: all characters except the minus sign, decimal point, and digits are ignored when searching for a floating-point number in the data stream. This is the default mode.

SKIP_NONE: Nothing is skipped and the stream is not touched unless the first waiting character is valid.

SKIP_WHITESPACE: Only tabs, spaces, line feeds and carriage return characters are skipped.

The second optional parameter is ignore : the indicated character is skipped in the search. This can be useful if there are known characters that we don’t want to use as delimiters in numbers.

Back to table of contents.

Serial.setTimeout() sets the maximum time in milliseconds to wait for serial data. The default value is 1000ms.

long time = 800; // 800ms

void setup()
{
  Serial.begin(9600);
  Serial.setTimeout(time);
}
void loop()
{
  
}

Back to table of contents.

Serial.peek() returns the decimal value of the next byte (character) of incoming serial data without removing it from the internal serial buffer. That is, successive calls to Serial.peek() return the same character as the next call to Serial.read(). So Serial.peek() allows you to parse the next character without reading it to see if it’s relevant.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

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

void loop()
{
  if(Serial.available() > 0) 
  {
    if(isDigit(Serial.peek()))
    {
      Serial.println("This is a number!");
      char myChar = Serial.read();
      Serial.println(myChar);
    }
    else
    {
      Serial.println("It's not a number!");
      Serial.read();   // this will flush the incoming buffer
    }
  }
}

Back to table of contents

The serialEvent() function is automatically called at the end of loop() if there is serial data in the serial buffer. The following example extracts the number characters from the serial buffer.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char myChar ="";
bool flag = false;

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

void loop() 
{
  if(flag) 
  {
    Serial.println(myChar);
    myChar = "";
    flag = false;
  }
}

void serialEvent() 
{
  if(Serial.available() > 0) 
  {
    myChar = Serial.read();
    if(isDigit(myChar))
    {
      flag = true;
    }
  }
}

Back to table of contents