Lab: Serial Input to an Arduino from Node.js

Introduction

In this lab, you’ll send asynchronous serial data from your personal computer to an Arduino microcontroller in order to control a digital output of the microcontroller. Once you’ve done that, you’ll also learn how to interpret ASCII-encoded numeric strings on the Arduino.

These videos will help to understand this lab:

The current version of this lab works with version 6.x.x of the node-serialport library.

What You’ll Need to Know

To get the most out of this Lab, you should be familiar with the basics of programming an Arduino microcontroller. If you’re not, review the Digital Input and Output Lab, the Serial Output from an Arduino Lab, and perhaps the Getting Started with Arduino guide.

Things You’ll Need

An Arduino Uno. The USB connector is facing to the left, so that the digital pins are on the top of the image, and the analog pins are on the bottom.
An Arduino Uno.
Three short pieces of hookup wire: one is clad in red insulation, one in blue, and one in black. All three have exposed ends approximately 5mm long.
22AWG hookup wire
LEDs. Shown here are four LEDs. The one on the right is an RGB LED. You can tell this because it has four legs, while the others have only two legs.
LEDs. Shown here are four LEDs. The one on the right is an RGB LED. You can tell this because it has four legs, while the others have only two legs.

The video Video: Serial 3 – DIY Protocol covers the same material as this lab.

Prepare the breadboard

Connect power and ground on the breadboard to power and ground from the microcontroller. On the Arduino module, use the 5V and any of the ground connections:

An Arduino Uno on the left connected to a solderless breadboard, right. The Uno's 5V output hole is connected to the red column of holes on the far left side of the breadboard. The Uno's ground hole is connected to the blue column on the left of the board. The red and blue columns on the left of the breadboard are connected to the red and blue columns on the right side of the breadboard with red and black wires, respectively. These columns on the side of a breadboard are commonly called the buses. The red line is the voltage bus, and the black or blue line is the ground bus.
An Arduino Uno on the left connected to a solderless breadboard, right.

Add the LED

Related Video: DIY Serial protocol

Connect an LED and resistor to pin 11 of the Arduino through a 220-ohm resistor. If you prefer an audio output, you can use a speaker instead. Appropriate code changes will be mentioned below:

Schematic view of an Arduino connected to an LED. Digital pin 5 is connected to a 22-ohm resistor. The other side of the resistor is connected to the anode (long leg) of an LED. The cathode of the LED is connected to ground.
Schematic view of an Arduino connected to an LED.
Breadboard view of an Arduino connected to an LED. The +5 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +5 volts is connected to the left outer side row (the voltage bus) and ground is connected to the left inner side row (the ground bus). The side rows on the left are connected to the side rows on the right using red and black wires, respectively, creating a voltage bus and a ground bus on both sides of the board. A blue wire connects Digital to a 22-ohm resistor that straddles the center divide of the breadboard in row 17. The other side of the resistor is connected to the anode (long leg) of an LED. The LED is mounted in rowsd 16 and 17 of the right side of the center section of the board. a black wire connects the cathode's row, row 16, to the ground bus on the right side of the board.
Breadboard view of an Arduino connected to an LED.

Program the Microcontroller to Read Serial Input

Related Video: Serial.available()
To program the Arduino to read serial input, you use the Serial.available() command. The .available() command returns the number of bytes that are available in the Arduino’s serial buffer that you haven’t read yet. When there are bytes available, you can read them using Serial.read().

In the setup() function of your program, initialize serial communications using Serial.begin(). Set the LED’s pin to be an output using pinMode() as well. Then in the setup, check how many bytes are available in the serial buffer using Serial.available() like so:

void setup() {
 Serial.begin(9600);   // initialize serial communications
 pinMode(11, OUTPUT);  // set digital pin 11 to be an output, to control the LED
}

void loop() {
 if (Serial.available() > 0) {

 }
}

Interpret the Incoming Serial Bytes

Related Video: reading the bytes in Arduino
Inside the if statement that checks Serial.available(), you’ll interpret the bytes as they come in. First, read the incoming bytes using Serial.read(). The serial buffer is a First-in, First-out buffer, or a FIFO buffer, meaning that the first byte that the computer sends is the first byte that the Arduino can read:

Here’s how to read the incoming bytes and interpret them:


void loop() {
 if (Serial.available() > 0) {
   char input = Serial.read();  // read first available byte into a variable
   if (input == 'H') {          // if the variable equals H, or ASCII 72
    digitalWrite(11, HIGH);     // turn on the LED
   }
   if (input == 'L') {          // if the variable equals L, or ASCII 76
    digitalWrite(11, LOW);      // turn off the LED
   }
 }
}

This sketch now reads the first available byte  into the variable input, then evaluates the variable. If input is equal to 72, which is the ASCII letter H, it turns on the LED. If input equals 76, or ASCII L, it turns the LED off.

GitHub repository for this sketch

Send Bytes to the Microcontroller

Related Video: uploading the sketch to the Arduino

Once you’ve uploaded this to the board, open the serial monitor. If you’re using the Arduino Serial Monitor to read and write serial data, make sure the line ending tab is set to “no line ending” like so:

Screenshot of the Arduino IDE Serial Monitor line ending option. The "no line ending" option is chosen.
Screenshot of the Serial Monitor line ending option

If you prefer to use a command line interface for serial communication, you can do that using the screen command.

Type H or L in the text input bar at the top, then hit enter. You should see the LED turn on when you send H, and turn off when you send L. You’ll notice that if you send lower case h or l, nothing happens. That’s because you didn’t check for those values. In ASCII, uppercase letters and lowercase letters each get different values. Uppercase H is 72, for example, but lowercase h is 104.

The serial monitor isn’t the only program that can send bytes to your microcontroller. Any program that can communicate over asynchronous serial communication can be used to send data. So if you’re using Processing, or Max/MSP, or node.js, you can control this simple Arduino program serially.

Change the Brightness of the LED Bytes Serially

The microcontroller reads all incoming bytes as values from 0 to 255. In the example above, you saw how to interpret those values as ASCII characters. But you can use the byte values any way you wish. Change the loop of your program as shown below:

 void loop() {
 // put your main code here, to run repeatedly:
 if (Serial.available() > 0) {
 char input = Serial.read();
 // use the value of the incoming byte to control the LED's brightness:
 analogWrite(11, input);
 }
}

GitHub Repository for this sketch

Upload this new sketch and open the serial monitor. When you send characters now, what’s happening? The LED’s brightness might be jumping around, seemingly randomly.  Lower case letters toward the end of the alphabet will make the LED slightly brighter, and uppercase ones toward the beginning will make it dimmer. The lower the value, the lower the brightness of the LED. a space, which is ASCII 32, will make the LED very dim, while a tilde (~), which is ASCII value 126, will make it brighter.

Related Video: reading a byte from the computer in Arduino

Advanced Serial Input: Parsing Numeric Strings

But what if you want to send an ASCII-encoded numeric string?  Why doesn’t the LED turn on to full brightness when you type “255”?  Even though you interpret the characters as one number, the Arduino interprets them as three bytes, with the values 50 (“2” = ASCII 50), 53 (“5” = ASCII 53), and 53. How do you get the Arduino to convert these strings as numbers?

You can use the Serial.parseInt() function to interpret ASCII numeric strings. This function will read all incoming bytes looking for a numeric character, and when it finds one, it will keep looking until it finds the next non-numeric character. Then it will interpret all the numeric characters it found as one number. Change your sketch’s loop as follows:

 void loop() {
 // put your main code here, to run repeatedly:
 if (Serial.available() > 0) {
 int input = Serial.parseInt();
 // use the value of the incoming byte to control the LED's brightness:
 analogWrite(11, input);
 }
}

GitHub Repository for this sketch

Then send in a numeric string, like 255 or 10. You should see the LED get much brighter with 255, and much dimmer with 10. If you send 0, the LED should turn off. Instead of interpreting your data byte-by-byte, .parseInt() is looking for strings of numbers and interpreting them. You can even give it multiple strings separated by non-numeric characters. Try the following strings:

10,127,255
0 255 0
12-250-3

You can separate your numbers however you wish. You could even look for multiple different numbers with multiple variables, like this:

 void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available() > 0) {
   int red = Serial.parseInt();
   int green = Serial.parseInt();
   int blue = Serial.parseInt();
  }
}

With the code above, if you sent three comma-separated values, you’d be able to set the three variables red, green, and blue independently.

Serial.setTimeout()

You may notice that .parseInt() is slow to respond. It has a timeout that defaults to one second, waiting for incoming data. You can speed it up by using Serial.setTimeout() to set the timeout in milliseconds. In your setup, right after Serial.begin(), try a Serial.setTimeout(10) to set the timeout to 10 milliseconds. This is generally good for most programs that might be sending ASCII strings to the microcontroller.

Serial Control from Node.js

If you’re familiar with node.js and the node-serialport library, perhaps because you’ve already tried the Serial to node.js lab, upload the following Arduino sketch:

 void setup() {
 // put your setup code here, to run once:
 Serial.begin(9600);
 Serial.setTimeout(10);
 pinMode(11, OUTPUT);
}

void loop() {
 // put your main code here, to run repeatedly:
 if (Serial.available() > 0) {
 char input = Serial.parseInt();
 // use the value of the incoming byte to control the LED's brightness:
 analogWrite(11, input);
 }
}

Now try the following node.js script (you’ll need to install node-serialport using npm as you did in the Serial to node.js lab). Save this as serialOutput.js:

 // serial port initialization:
var SerialPort = require('serialport'); // include the serialport library
var portName = process.argv[2]; // get the port name from the command line
var myPort = new SerialPort(portName, 9600);// open the port

// these are the definitions for the serial events:
myPort.on('open', openPort); // called when the serial port opens

function openPort() {
    var brightness = 0; // the brightness to send for the LED
    console.log('port open');
    console.log('baud rate: ' + myPort.options.baudRate);

    // since you only send data when the port is open, this function
    // is local to the openPort() function:
    function sendData() {
         // convert the value to an ASCII string before sending it:
         myPort.write(brightness.toString());
         console.log('Sending ' + brightness + ' out the serial port');
         // increment brightness by 10 points. Rollover if > 255:
         if (brightness < 255) {
              brightness+= 10;
         } else {
              brightness = 0;
         }
    }
    // set an interval to update the brightness 2 times per second:
    setInterval(sendData, 500);
}

Make sure the serial monitor in Arduino is closed, then run this by typing the following on the command line:

$ node serialOutput.js portname

Replace portname with the name of your serialport. When this runs, you should see the LED getting ten percent brighter every half a second, then go out when it reaches the brightest.

Originally written on August 30, 2015 by Tom Igoe
Last modified on August 21, 2018 by Tom Igoe