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.

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

Things You’ll Need

Figure 1-3 are basically what you need for this lab.

Photo of an Arduino Nano 33 IoT module. The USB connector is at the top of the image, and the physical pins are numbered in a U-shape from top left to bottom left, then from bottom right to top right.
Figure 1: Arduino Nano 33 IoT
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.
Figure 2: 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.
Figure 3: 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.

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(Figure 4):

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.
Figure 4: An Arduino Uno on the left connected to a solderless breadboard, right.
Arduino Nano on a breadboard.
Figure 5. Breadboard view of Arduino Nano on a breadboard.

As shown in Figure5, the +3.3 volts and ground pins of the Arduino are connected by red and black wires, respectively, to the left side rows of the breadboard. +3.3 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.


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 (Figure6-7):

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.
Figure 6: 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.
Figure 7: Breadboard view of an Arduino connected to an LED.

Breadboard view of an LED connected to digital pin 5 of an Arduino Nano.
Figure 8. Breadboard view of an LED connected to digital pin 5 of an Arduino Nano.

Figure 8: Breadboard view of an LED connected to digital pin 5 of an Arduino Nano. The Nano straddles the center of the breadboard in the first fifteen rows. The Nano’s voltage pin (physical pin 2) connects to the board’s voltage bus, and the Nano’s ground pin (physical pin 14) connects to the board’s ground bus. The LED is in the right center of the board, with its anode in one row and the cathode in the next. A 220-ohm resistor connects the LED’s anode to a wire connecting to digital pin 5. The LED’s cathode is connected to the ground bus.


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) {
    byte 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.

Note: What Do the Single Quotes Mean?

In the C programming language (and by extension, in Arduino, since Arduino based on C), you can put a single ASCII character in single quotes and the compiler will interpret it as its numeric value. This can be handy when you know you want to compare a byte to an ASCII character, but can’t remember the numeric value of the ASCII character.

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(Figure 9):

Screenshot of the Arduino IDE Serial Monitor line ending option. The "no line ending" option is chosen.
Figure 9: 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) {
    byte input = Serial.read();
    // use the value of the incoming byte to control the LED's brightness:
    analogWrite(11, input);
  }
}

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);
  }
}

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.