Understanding hardware and software serial ports

I’m still seeing frequent posts, mostly from new members of the forum, who are confused about how to add WiFi or Bluetooth connectivity to devices like the Arduino Uno, Nano or Mega, or from people who are trying to use serial communication with some other type of peripheral.

I thought I’d try to put together some guidance on how to do this properly.

First things first though – if you’re using a device such as an Uno, Nano or Mega that doesn’t have built-in internet connectivity then you should seriously consider using other hardware such as the NodeMCU or ESP32 boards. Life is much simpler when you use this type of hardware, and they are usually cheaper than an Uno and an ESP-01 WiFi module.

Basic Principals

Communication Speed (Baud Rate)

Your MCU board (Uno etc) and your peripheral device need to be talking to each other at the same rate. If not then they won’t be able to understand each other.

If you’re using a SoftwareSerial port to communicate with your peripheral then don’t use a baud rate higher than 9600, because the Uno etc doesn’t have enough processing power to emulate a serial port at higher communication speeds.

Your peripheral device can usually be re-configured to use a different baud rate, but I’m not going to cover that process in this tutorial as there are too many hardware variations to cover. You’ll usually need to issue an AT command to your peripheral to change its baud rate, so google how to do that for your hardware.

Tx and Rx Wiring

You always connect the Transmit (Tx) pin on one device to the Receive (Rx) pin on the other. Think of it like a telephone, you speak into the mouthpiece and the sound comes out of the speaker at the other end.

Your ESP-01 needs to be running the factory “AT” firmware

If you’re connecting your MCU board (Uno etc) to an ESP-01 to use the ESP-01 as a WiFi modem, then the ESP-01 needs to be running the default factory firmware. If you upload a sketch to the ESP-01 then you will overwrite the AT firmware and it won’t understand the “AT” commands that your MCU board is sending to it.

If your factory AT firmware has been overwritten then you will need to re-install the AT firmware. This can not be done using the Arduino IDE, it needs to be done in a different way.

I’m not going to cover how to re-install AT firmware in this tutorial. It’s been covered many times on the forum and on the internet.

Your peripheral device needs a dedicated serial port

Your peripheral device will be listening for “AT” commands, and if debug messages such as serial print or Blynk print commands are sent to the same serial port that your peripheral is connected to, it will jumble-up the communication. This will result in either a failed connection to Blynk, or a dropped connection when debug data is sent to the peripheral.

An FTDI TTL to USB adapter is very useful

If you need to re-program, test or re-configure your peripheral device then you’ll probably need an FTDI adapter. This allows you to send and receive data via a USB port on your computer to your peripheral or your board. The FTDI is more correctly referred to as a TTL to USB adapter, as it converts TTL (logic level) signals to a USB connector that ban be plugged into your computer. For the sake of simplicity, I’ll use the term FTDI adapter.

If you’re using a board with just one hardware serial port (such as an Uno or a Nano) then you’ll probably want to use the built-in FTDI adapter (which is connected internally to the USB port on the Uno / Namo) for debugging, then connect your peripheral via a SoftwareSerial port. This allows you to view debug messages on your PC without separate FTDI adapter. However, if your peripheral uses a baud rate higher than 9600 by default then you won’t be able to connect it to your MCU board using a SoftwareSerial port. That means you’ll need to use the hardware serial port for your peripheral, and a SoftwareSerial port for debugging. To view this debug data, you’ll need an external FTDI adapter connected to your SoftwareSerial port.

Spending a few Dollars/Euros etc on an FTDI adapter is a good investment if you are going to be working with an Uno, Nano or any peripheral device that connects via serial and may need to be re-configured (but that few dollars would also buy you an ESP32 board instead :wink:)

Connecting an Uno/Nano to an ESP-01

A typical setup uses an Uno or Nano (which have just one hardware serial port) with an ESP-01 to give WiFi connectivity.

Scenario 1 – Hardware serial port is used for debugging, SoftwareSerial is use for the peripheral

The simplest approach is to keep the hardware serial port for debugging and uploading code, and create a SoftwareSerial port to connect the ESP-01 to. However, this will only work if your ESP-01 is set to communicate at 9600 baud, as SoftwareSerial doesn’t work effectively at higher speeds on an underpowered board like the Uno or Nano.

A common mistake is to see that the Uno/Nano has pins marked Rx and Tx and connect the ESP-01 to these. These Rx & Tx pins (GPIO0 and GPIO1) are connected to the USB connector on the Uno/Nano via the onboard FTDI adapter, so in this scenario they need to be left unconnected.

A typical Blynk sketch for this scenario would look like this

#define BLYNK_TEMPLATE_ID           "TMPLxxxxxx"
#define BLYNK_DEVICE_NAME           "Device"
#define BLYNK_AUTH_TOKEN            "YourAuthToken"

// Send Blynk user messages to the hardware serial port…
#define BLYNK_PRINT Serial 

#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>

char auth[] = BLYNK_AUTH_TOKEN;

char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";

// Create a SoftwareSerial port on pins 2 & 3 and call it EspSerial…
#include <SoftwareSerial.h>
SoftwareSerial EspSerial(2, 3); // RX, TX

// Define your ESP8266 baud rate (Max 9600):
#define ESP8266_BAUD 9600

// Tell the Blynk library to use the SoftwareSerial port for WiFi..
ESP8266 wifi(&EspSerial);

void setup()
{
  // Initialise the debug (hardware) serial port
  Serial.begin(115200);

  // Initialise the SoftwareSerial port…
  EspSerial.begin(ESP8266_BAUD);
  delay(10);

  Blynk.begin(auth, wifi, ssid, pass);
}

void loop()
{
  Blynk.run();
}

This line of code…

SoftwareSerial EspSerial(2, 3); // RX, TX

tells the sketch that we are going to connect the ESP-01 to pins 2 and 3 on the Uno/Nano. Remember that pin 2 (SoftwareSerial Rx) will connect to the Tx pin on the ESP-01 and that pin 3 (SoftwareSerial Tx) will connect to the Rx pin on the ESP-01.

With this setup, if you want to send your own debug messages to the serial monitor then you would use the regular Serial.print() command, and you can see that we use #define BLYNK_PRINT Serial to tell the Blynk library to send Blynk related data to the hardware serial port.

Scenario 2 – Hardware serial port is used for the peripheral, SoftwareSerial is use for debugging (using an FTDI adapter)

This approach is normally used when your peripheral needs to communicate at a higher baud rate than 9600. This usually occurs when you are unable to change the baud rate of the peripheral device. Of course, this can occur when you don’t have an FTDI adapter available to re-configure the peripheral, but if you don’t have an FTDI adapter available then you won’t be able to see the debug messages from Blynk either.

In this scenario, the ESP-01 will be connected to pins 0 & 1 (labelled Rx and Tx on the board). The Rx on the Uno/Nano will connect to the Tx on the ESP-01 and the Tx on the Uno/Nano will connect to the Rx on the ESP-01.

You will probably have to disconnect the ESP-01 from the Uno/Nano when you want to upload a new sketch to the Uno/Nano, as the ESP-01 will probably interfere with the upload process.

A typical sketch for this scenario would look like this…

#define BLYNK_TEMPLATE_ID           "TMPLxxxxxx"
#define BLYNK_DEVICE_NAME           "Device"
#define BLYNK_AUTH_TOKEN            "YourAuthToken"

// Send Blynk user messages to the SoftwareSerial port…
#define BLYNK_PRINT DebugSerial 

#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>

char auth[] = BLYNK_AUTH_TOKEN;

char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";

// Create a SoftwareSerial port on pins 2 & 3 and call it DebugSerial…
#include <SoftwareSerial.h>
SoftwareSerial DebugSerial(2, 3); // RX, TX

// Define your ESP8266 baud rate:
#define ESP8266_BAUD 38400

// Tell the Blynk library to use the Serial port for WiFi..
ESP8266 wifi(&Serial);

void setup()
{
  // Initialise the debug (SoftwareSerial) port (Max 9600)
  Serial.begin(9600);

  // Initialise the hardware Serial port…
  Serial.begin(ESP8266_BAUD);
  delay(10);

  Blynk.begin(auth, wifi, ssid, pass);
}

void loop()
{
  Blynk.run();
}

To view the debug messages that are being sent to the SoftwareSerial port (pins 2 & 3) you will need an FTDI adapter connected to these pins (pin 2 (Rx) to the FTDI Tx pin, pin 3 (Tx) to the FTDI Rx pin).

With this setup, if you want to send your own debug messages to the serial monitor then you would use the DebugSerial.print() command. If you used Serial.print() command instead then these would go to the ESP-01 and probably cause a disconnection from Blynk. You’ll also see that #define BLYNK_PRINT DebugSerial is used in the sketch to tell the Blynk library to send Blynk related data to the SoftwareSerial port.

Connecting an Arduino Mega to an ESP-01

The Mega has three hardware serial ports, so there is no need to use SoftwareSerial in normal circumstances.

The ports are referenced as…

Serial Pins 0 (Rx) and 1 (Tx) – same as the Uno/Nano

Serial1 Pins 19 (Rx) and 18 (Tx)

Serial2 Pins 17 (Rx) and 16 (Tx)

I believe that some Chinese copies of the Mega have some of these pins mis-labelled, so I’d recommend checking your board against the official Arduino pinout diagram.

Only the Serial port (pins 0 & 1) is connected to the USB port via the onboard FTDI adapter, so this should be used as your debug port.

A typical Blynk sketch for the Mega would look like this…

#define BLYNK_TEMPLATE_ID           "TMPLxxxxxx"
#define BLYNK_DEVICE_NAME           "Device"
#define BLYNK_AUTH_TOKEN            "YourAuthToken"

// Send Blynk user messages to the hardware serial port…
#define BLYNK_PRINT Serial 

#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>

char auth[] = BLYNK_AUTH_TOKEN;

char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";

// Define your ESP8266 baud rate:
#define ESP8266_BAUD 38400

// Tell the Blynk library to use the  Hardware Serial port 1 for WiFi..
ESP8266 wifi(&Serial1);

void setup()
{
  // Initialise the debug serial port
  Serial.begin(115200);

  // Initialise the Hardware serial1 port…
  Serial1.begin(ESP8266_BAUD);
  delay(10);

  Blynk.begin(auth, wifi, ssid, pass);
}

void loop()
{
  Blynk.run();
}

With this setup, the ESP-01 will be connected to pins 19 and 18 (Pin 19 (Mega serial port 1 Rx) will connect to the ESP-01 Tx pin and Pin 18 (Mega serial port 1 Tx) will connect to ESP-01 Rx pin).

With this setup, if you want to send your own debug messages to the serial monitor then you would use the regular Serial.print() command and once again we that we use #define BLYNK_PRINT Serial to tell the Blynk library to send Blynk related data to the hardware serial port.

Connecting an Uno/Nano or Mega to a Bluetooth adapter

The same principals apply when using a Bluetooth serial adapter such as the HC-0x range, as when a an ESP-01 is used.

Note that the new version of Blynk doesn’t currently support Bluetooth as a connection method (and part of me hopes that it never will), so you’ll need to be using the unsupported Blynk Legacy product, which doesn’t allow new user accounts to be created.

When using Blynk Legacy with Bluetooth, don’t forget to add the BT/BLE widget to the mobile dashboard and to use this widget to establish the connection with your device.

Connecting an Uno/Nano or Mega via a USB connection to a computer (BlynkSimpleStream)

This connection method is only useful for initial testing of Blynk, as it requires an internet connected computer to be used as a bridge between the Uno/Nano/Mega. This computer needs to be on constantly and running a script to allow the computer to fulfil this bridge role.

If you don’t have an external FTDI then your only option is to connect the USB port on the Uno/Nano/Mega to the computer. This means that Serial.print() and #define BLYNK_PRINT Serial commands can’t be used within your sketch, as they will interfere with the communication to the computer via the serial port on the board.

If you do have an external FTDI then this can be used to view debug messages.
With an Uno or Nano you would need to create a SoftwareSerial port. Note that, as explained above, if the USB port on the Uno/Nano is being used to connect to Blynk via the computer then the onboard USB port uses pins 0 and 1 (Rx and Tx), so the SoftwareSerial port would need to use different pins.
With a Mega, one of the hardware serial ports could be used for the FTDI, but this also can’t be pins 0 and 1 as these are connected to the onboard USB port.

Once these changes have been made then the #define BLYNK_PRINT command can be modified to send debug messages to the SoftwareSerial or hardware serial port that your FTDI is connected to, and debug messages can also be used be printed to the same port.

Note that with Blynk IoT, the script provided for this USB connection method hasn’t been updated and still points to the Blynk Legacy server. To use this script with Blynk IoT you will need to edit the script before running it.

If you’re using Windows then the process is as follows:

  1. Go to the folder where your Blynk library is installed (usually Documents/Arduino/Libraries/Blynk) and locate the Scripts folder.
  2. Find the file called blynk-ser.bat and right-click then choose Edit
  3. Locate the line that says set SERV_ADDR=blynk-cloud.com and edit it to read set SERV_ADDR=blynk.cloud
  4. Save and close the file.

The script is launched by double-clicking the .bat file, or choosing Tools > Blynk: Run USB Script from the Arduino IDE.

If you’re using an OS other than Windows then you’ll need to edit the blynk_ctrl.py or blynk-ser.sh in the same way.

Summary

The important things to remember are:

  • The board and the peripheral need to be talking to each other at the same baud rate

  • The port that is used can’t be used for anything else (debug prints for example) as this will interfere with the AT commands passing between the board and the peripheral device

  • Always connect RX to Tx and Tx to Rx

  • SoftwareSerial doesn’t work reliably on an Uno/Nano/Mega at speeds higher than 9600 baud

  • The peripheral need to be expecting AT communications on its Rx pin, so an ESP-01 that isn’t running the factory AT firmware won’t work.

  • Unless you have an extremely good reason to use an Uno/Nano/Mega with Blynk then you are much better using an IoT enabled board such as a NodeMCU or ESP32 (and the NodeMCU or ESP32 is usually much cheaper too).

PLEASE - Don’t post general Uno/ESP-01 questions in this topic

I’ll leave this topic open for constructive comments, as I’d like to know if there are any mistakes, ambiguities or important areas that I’ve forgotten to cover.
However, I’d like the topic to be a simple reference for others to follow, so don’t want it to be cluttered-up with “I get an ESP not responding message, please help me” type of comments. If you post these types of comments then they will simply deleted.

Pete.

5 Likes