Lab: Serial Input to an Arduino from Node.js

Originally written on August 30, 2015 by Tom Igoe
Last modified on August 27, 2016 by Tom Igoe

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:

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

For this lab you'll need:
hookup_wire arduino 
22-AWG hookup wire Arduino module LED

Related video

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:

LabTemplate_bb

Add the LED

Related Video

Connect an LED and resistor to pin 11 of the Arduino like so:

Schematic view Arduino with LED on digital pin 11

Program the Microcontroller to Read Serial Input

Related Video
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
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

Once you’ve uploaded this to the board, open the serial monitor. Make sure the line ending tab is set to “no line ending” like so:

line-ending-tab

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

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
     SerialPort = serialport.SerialPort, // make a local instance of serial
     portName = process.argv[2],         // get the port name from the command line
     portConfig = {
         baudRate: 9600,
         // call myPort.on('data') when a newline is received:
         parser: serialport.parsers.readline('\n')
     };

// open the serial port:
var myPort = new SerialPort(portName, portConfig);

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.