How to Use Arduino Serial Ports

Arduino boards such as the Uno, MEGA2560 and Due all have a serial port that connects to the USB device port on the board. This port allows sketches to be loaded to the board using a USB cable. Code in a sketch can use the same USB / serial port to communicate with the PC by using the Arduino IDE Serial Monitor window, or a Processing application for example. The USB port appears as a virtual COM port on the PC.

This article shows how to use Arduino serial ports when additional serial ports are needed for a project.

Arduino Serial Ports Available

The serial port for programming the Arduino mentioned above is a hardware serial port. The microcontroller on the Arduino board has a hardware serial port built-in, so that after the port has been initialized by software, a byte sent to the port will be sent out serially by the hardware.

The Arduino Uno has only one hardware serial port because the microcontroller used on the Uno has only one built-in serial port. The Arduino MEGA 2560 and Arduino Due both have 3 extra hardware serial ports.

Serial Port Technical Details

The hardware serial ports referred to here are UART (Universal Asynchronous Receiver Transmitter) ports. They may be referred to as USART (Universal Synchronous Asynchronous Receiver Transmitter) ports in the microcontroller documentation if they are configurable in both synchronous and asynchronous modes.

Arduino Uno Serial Port

This image shows the only serial port available on the Arduino Uno highlighted in red. The port connects through a USB chip to the USB device port.

Arduino Uno Serial Port

Arduino Uno Serial Port

Arduino MEGA 2560 and Due

Both the MEGA 2560 and Due have 4 serial ports in total. One that connects through a USB port chip to the USB device port on the board and three extra serial ports that connect to pins on one of the pin headers of the board.

Arduino Due Serial Ports

Arduino Due Serial Ports

 

Arduino MEGA 2560 Serial Ports

Arduino MEGA 2560 Serial Ports

Pins 0 and 1 of the Due and MEGA connect serial port 0 through to the USB device port so that these Arduino boards are compatible with the pin numbering of the Uno and therefore with Arduino shields.

The extra serial ports are ports 1 to 3 with each port having a transmit and receive pin.

It is important to be aware that the MEGA 2560 serial port pins use 5V voltage levels, but the Due uses 3.3V voltage levels.

How to Use Additional Arduino Serial Ports

An extra serial port can be used on an Arduino Uno, but must be simulated in software by using the SoftwareSerial library.

Arduino Uno

The following code is taken from the article on serial communications with the GT-511C3 fingerprint scanner which connects the fingerprint scanner to a software serial port on an Arduino Uno.

#include <SoftwareSerial.h>

SoftwareSerial gtSerial(8, 7); // Arduino RX, Arduino TX

void setup() {
  Serial.begin(9600);    // serial / USB port
  gtSerial.begin(9600);  // software serial port
}

byte rx_byte = 0;        // stores received byte

void loop() {
  // check if byte available from USB port
  if (Serial.available()) {
    rx_byte = Serial.read();
    // send a byte to the software serial port
    gtSerial.write(rx_byte);
  }

  // check if byte available on the software serial port
  if (gtSerial.available()) {
    // get the byte from the software serial port
    rx_byte = gtSerial.read();
    Serial.write(rx_byte);
  }
}

To use the software serial port, first the header file for the software serial library must be included.

#include <SoftwareSerial.h>

Next create the software serial port, selecting the Arduino pins to use for receive (RX) and transmit (TX). Here pin 8 has been set as the receive pin and pin 7 as the transmit pin.

SoftwareSerial gtSerial(8, 7);

The software serial port had been given the name gtSerial which will be used in the sketch to refer to this serial port.

The port can now be checked for incoming data.

if (gtSerial.available()) {

If data is available, it can be read from the port.

rx_byte = gtSerial.read();

Data bytes can also be sent on the port.

gtSerial.write(rx_byte);

How to Use Additional Serial Ports on the Arduino MEGA 2560 and Due

The additional hardware ports on the Arduino MEGA 2560 and Due can be used in the same way as the main USB serial port is used in sketches, only changing the name of the port. The USB serial port, or serial port 0 is referred to as Serial in sketches. To use serial port 1, the name changes to Serial1. Serial ports 2 and 3 are referred to as Serial2 and Serial3.

This sketch shows serial port 3 being used which transmits on pin 14 of the MEGA or Due and receives on pin 15.

void setup() {
  // initialize serial ports
  Serial.begin(9600);    // USB serial port 0
  Serial3.begin(9600);   // serial port 3
}

byte rx_byte = 0;        // stores received byte

void loop() {
  // check for data byte on USB serial port
  if (Serial.available()) {
    // get byte from USB serial port
    rx_byte = Serial.read();
    // send byte to serial port 3
    Serial3.write(rx_byte);
  }
  // check for data byte on serial port 3
  if (Serial3.available()) {
    // get a byte from serial port 3
    rx_byte = Serial3.read();
    // send the byte to the USB serial port
    Serial.write(rx_byte);
  }
}

The additional serial ports are immediately available in the sketch without having to include any libraries.

Serial port 3 must first be initialized to the desired baud rate.

Serial3.begin(9600);

The port can be checked for incoming data.

if (Serial3.available()) {

If a byte has arrived on the serial port, it can be read.

rx_byte = Serial3.read();

A byte can be written to the serial port.

Serial.write(rx_byte);

Arduino Serial Port Resources

Arduino Website References for Software and Hardware

Projects, Articles and Tutorials

Arduino MEGA Ethernet Web Server for Controlling 24 Outputs

In this tutorial, an Arduino MEGA 2560 and Ethernet shield are used to make a web server that hosts a web page that allows 24 outputs to be controlled using checkboxes. The tutorial on the Arduino MEGA web server contains the circuit diagram and all of the source code for the project.

This tutorial was written to answer a question on the blog about the Arduino web server tutorial.

An image of the web server with the web page used to control 24 LEDs is shown below.

24 Output Arduino MEGA Web Server using the Ethernet Shield

24 Output Arduino MEGA Web Server using the Ethernet Shield

Extending LED Output Range on Arduino MEGA 2560 Web Server

This is a solution to the problem that users found when using an Arduino MEGA 2560 with the Switching LEDs on from a Web Page tutorial. The problem is when outputs (or LEDs connected to outputs) greater than 9 are used, they will not switch on. This is the case with the Arduino MEGA 2560 which increases the number of input/output pins above the range of the Arduino Uno by I/O from 14 to 53.

The Problem

The problem is that in the original sketch, the CheckLEDs() function only checks for output (or LED) numbers from 0 to 9. It actually checks for the ASCII characters ‘0’ to ‘9’ as shown below:

// get the state of the LED checkboxes from the HTTP request
void CheckLEDs()
{
    for (byte led_num = 0; led_num < sizeof(LED_pins); led_num++) {
        if ((HTTP_req.charAt(9) == (LED_pins[led_num] + '0')) &&
                    (HTTP_req.charAt(16) == (LED_pins[led_num] + '0'))) {  // LED box is checked
            LED[led_num] = 1;
        }
        else if (HTTP_req.charAt(9) == (LED_pins[led_num] + '0')) {        // LED box is unchecked
            LED[led_num] = 0;
        }
    }
}

 

The Solution

The solution is to check for numbers that are greater than 9 i.e. 2 digit numbers. To do this, first a check is done to determine whether the output being switched on is a single or two digit number. The ASCII numbers are then converted to integers (although they are stored in char variables).

The full sketch is shown below:

/*--------------------------------------------------------------
  Program:      eth_websrv_LED2_MEGA

  Description:  Arduino web server that serves up a web page
                allowing the user to control LEDs
  
  Hardware:     - Arduino MEGA 2560 and official Arduino
                  Ethernet shield. Should work with other
                  Arduinos and compatible Ethernet shields.
                - LED and resistor in series connected between
                  Arduino pin 2 and GND. Second LED connected
                  to pin 30. Third LED connected to pin 53.
                
  Software:     Developed using Arduino 1.0.6 software
                Should be compatible with Arduino 1.0 +
  
  References:   - WebServer example by David A. Mellis and 
                  modified by Tom Igoe
                - Ethernet library documentation:
                  http://arduino.cc/en/Reference/Ethernet
                - Derived from eth_websrv_LED2 at:
                  http://blog.startingelectronics.com/?p=598

  Date:         25 February 2014
 
  Author:       W.A. Smith, http://startingelectronics.org
--------------------------------------------------------------*/

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

byte mac[] = { 0x90, 0xA2, 0x00, 0x00, 0x00, 0x01 };    // MAC address
IPAddress ip(192,168,0, 20);                               // IP address

EthernetServer server(80);

char char_in = 0;    // used to store a character from the Ethernet port
String HTTP_req;     // stores the received HTTP request

// add your LED outputs to be switched here
const byte LED_pins[] = {2, 30, 53};     // Arduino pins used as ouputs for LEDs
byte LED[sizeof(LED_pins)] = {0};        // the state of each LED

void setup()
{
//    Serial.begin(9600); ////////////debug
  
    Ethernet.begin(mac, ip);
    server.begin();
    
    // set up the LED pins as outputs
    for (byte index = 0; index < sizeof(LED_pins); index++) {
        pinMode(LED_pins[index], OUTPUT);
    }
}

void loop()
{
    EthernetClient client = server.available();

    if (client) {
        while (client.connected()) {
            if (client.available()) {
                char_in = client.read();  // get a single character from the Ethernet port
                HTTP_req += char_in;      // build a string out of the received characters

                // answer first HTTP request immediately
                if (char_in == '\n') {
                    // respond to HTTP request
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println();
                    CheckLEDs();              // get state of LED checkboxes from web page
                    DisplayLEDs(&client);     // display checkboxes on web & write to LEDs
                    HTTP_req = "";      // delete string contents
                    client.stop();
                } // end if (char_in == '\n')
            } // end if (client.available()
        } // end while (client.connected())
    } // end if (client)
}

// get the state of the LED checkboxes from the HTTP request
void CheckLEDs()
{
    char num1, num2, num3, num4;
    
    num1 = HTTP_req.charAt(9);
    num2 = HTTP_req.charAt(10);
//    Serial.println(HTTP_req);///////////////debug
    
    // is it a 2 LED digit number?
    if ((num2 >= '0') && (num2 <= '9')) {
        // it is a 2 digit number, now get the 2nd 2 digit number
        num3 = HTTP_req.charAt(17);
        num4 = HTTP_req.charAt(18);
        // convert the two 2 digit ASCII numbers to integers
        num1 -= '0';
        num1 *= 10;
        num2 -= '0';
        num3 -= '0';
        num3 *= 10;
        num4 -= '0';
        num1 += num2;  // first number stored in num1
        num3 += num4;  // second number stored in num3
        
    }
    else {
        // single digit LED number
        // get the 2nd 1 digit number
        num3 = HTTP_req.charAt(16);
        // convert the numbers from ASCII to integer
        num1 -= '0';  // first number
        num3 -= '0';  // second number
    }
    for (byte led_num = 0; led_num < sizeof(LED_pins); led_num++) {
        if ((num1 == LED_pins[led_num]) && (num3 == LED_pins[led_num])) {  // LED box is checked
            LED[led_num] = 1;
        }
        else if (num1 == LED_pins[led_num]) {        // LED box is unchecked
            LED[led_num] = 0;
        }
    }
}

// write the HTML that includes the state of the LED checkboxes for displaying on the web browser
void DisplayLEDs(Client *client)
{
    // some CSS in the HTML to change colours and position of the box containing the LED checkboxes
    client->print("<div style=\"background:white; color:green; position: absolute; margin:20px; border: grey solid 2px; padding:0 10px 4px 10px;\">");
    client->print("<h1 style=\"font: normal 20px/150% Verdana, Arial, Sans-serif;\">LED Outputs</h1>");
    // send each LED checkbox in turn
    for (byte led_num = 0; led_num < sizeof(LED_pins); led_num++) {
        // use hidden checkbox so that unchecking a checkbox sends a value to the Arduino
        // if only a normal checkbox is used, nothing is sent when it is unchecked
        // both hidden and normal checkboxes are produced here for each LED
        client->print("<form> <input type=\"hidden\" name=\"LED");
        client->print(LED_pins[led_num], DEC);
        client->print("\" value=\"0\"> <input type=\"checkbox\" name=\"LED");
        client->print(LED_pins[led_num], DEC);
        client->print("\" value=\"");
        client->print(LED_pins[led_num], DEC);
        client->print("\"");
        // write to the LED connected to the Arduino board
        if (LED[led_num]) {
            client->print(" checked ");             // part of HTML if checkbox is to be displayed checked
            digitalWrite(LED_pins[led_num], HIGH);  // switch LED on
        }
        else {
            digitalWrite(LED_pins[led_num], LOW);  // switch LED off
        }
        client->print(" onclick=\"submit();\">LED");
        client->print(LED_pins[led_num], DEC);
        client->print(" </form>");                 // end of HTML for 1 LED's form
    }
    client->print("</div>");                       // end of box containing LEDs
}

The images below show the hardware used to test the sketch as well as the web page that the sketch generates.

Arduino MEGA 2560 Web Server

Arduino MEGA 2560 Web Server

 

Arduino MEGA 2560 Web Page

Arduino MEGA 2560 Web Page

News: Solving the Arduino Ethernet Web Server Page Linking Problem

What’s happening at Starting Electronics? (14 June 2013)

I have been working on the sketch for part 10 of the Arduino Ethernet shield web server tutorial that many people could not get to work. The sketch allows the Arduino with Ethernet shield to host two web pages on the SD card. Each web page has a link to the other page and when clicked, should load the other page in the web browser.

The Problem

Firstly, there was no problem when I developed the code using Arduino software version 1.0.3, an Arduino Uno and Arduino Ethernet shield – everything worked. However, a number of people could not get the code to work as reported in the blog entry for the tutorial. I did not have any other Arduino hardware to test the code further, so could not get the problem to come up and then debug it.

New Hardware

Arduino Ethernet Board

After getting a new Arduino Ethernet board, and loading the sketch from part 10, the problems started appearing. The first web page loaded from the Arduino web server, but a blank page appeared in the web browser when the link to the second page was clicked. Compiling the sketch with Arduino software version 1.0.5 and trying to run the web server on the old hardware now resulted in the first web page not loading at all. Changing back to version 1.0.3 software solved the problem on the old hardware, but not on the new Arduino Ethernet board.

Arduino Mega 2560 Board

When testing the sketch on a new Arduino Mega 2560 with the original Ethernet shield the sketch worked with no problems.

Memory Sizes

It had been suggested by someone in the comments on the blog that the problem was with too little SRAM on the Uno board – changing to the Arduino Mega proved this. The SRAM sizes for the three boards that I have are as follows:

  • Arduino Uno – 2k Bytes SRAM
  • Arduino Ethernet – 2k Bytes SRAM
  • Arduino Mega 2560 – 8k Bytes SRAM

The Solution to the Problem

I had already suspected that using the String class in the sketch was the source of the problem and had mentioned a way of reducing the number of bytes that the String class object in the sketch was using in part 16 of the tutorial series. Restricting the number of bytes in the web page link example, however, made no difference.

The String Class Object

The String object was used to store the HTTP request from the web browser. The stored request could then be analysed later in the sketch to see which page the web browser was requesting. Restricting the String object to storing only the first 30 bytes of the HTTP request did not solve the problem. The only solution was to eliminate the use of the String class altogether.

My thinking in using the String class was that the sketch was small, so there should be no memory problems and it worked (at least on my hardware) – no need to write extra functions and make the sketch more complicated. The String class also had a method that made it easy to find out which web page was requested by searching in the stored HTTP request String for the web page name.

New String Functions

In the new sketch, the String class object was replaced by a char buffer with limited size. Two new functions were written to operate on the new buffer. One to clear the buffer and the other to search for a particular string in the buffer. This eliminated the need to use the String class at all. The function that searches for the string in the HTTP request buffer is used to find which web page the browser is requesting.

To see the new sketch, go to part 10 of the Arduino Ethernet web server tutorial: Arduino SD Card Web Server – Linking Pages.

IP Addresses

A few weeks ago, my ADSL router failed and I had to replace it. The old router used the address range 10.0.0.x and the new router now uses the address range 192.168.0.x. The new sketch now uses the new address range, so be sure to change the IP address in the sketch to suit your network. If the sketches were all working on your system at 10.0.0.20, but the updated sketches stop working, it is probably because the updated sketches are using the new IP address 192.168.0.20.

I will continue testing the remainder of the Arduino Ethernet web server tutorial using the Arduino Ethernet board and will eliminate the use of the String object from all sketches, which will hopefully make the code a lot more reliable and able to work across all the Arduino hardware.