(edit sidebar)
Intro to Physical Computing Syllabus

Research & Learning

Other Class pages

Shop Admin

ITP Help Pages
Tom's pcomp site
DanO's pcomp site


Serial Out using an Arduino

Overview

In this lab, you'll send data from a single sensor to a program on a personal computer. The program will graph the output of the sensor onscreen. This is a common way to find out how a sensor's output corresponds to the physical events that it senses.

(:toc Table of Contents:)

Parts

For this lab you'll need:

hookup wire
22-AWG hookup wire
Arduino module
Arduino Microcontroller
module
potentiometer
10Kohm potentiometer (or a different
form of analog sensor)


Connect the sensor

Connect your analog sensor to analog pin 0 like you did in the analog lab. A potentiometer is shown there because it's easy, but you might want to pick a sensor that's more interesting. IR distance rangers are fun for this exercise, for example. Force-sensing resistors are good as well.

Read and send the serial data

Program the Arduino module to read the analog sensor and print the results to the Serial monitor. Instead of using Serial.println(), however, use Serial.write() to send the sensor value serially.

void setup() {
    Serial.begin(9600);
}
void loop() {
    int analogValue = analogRead(A0) /4;      // read the pot value
    Serial.write(analogValue);        // print the value in the serial monitor as a binary value
}

You get a result that ranges from 0 to 255 instead of 0 to 1023. This means that the result will fit in a single byte. You'll see why that's convenient shortly.

Serial Monitor Screenshot
Serial monitor screenshot, showing garbage. What is happening?

When you open the serial monitor, you will see garbage characters. What's going on? The Serial.write() command doesn't format the bytes as ASCII characters. It sends out the binary value of the sensor reading. Each sensor reading can range from 0 to 1023; in other words, it has a 10-bit range, since 210 = 1024 possible values. Since that's more than the eight bits that can fit in a byte, you're dividing the value by 4 in the code above, to get a range from 0 to 255, or 28 bits.

So, for example, if the sensor reading's value is 234, then the Serial.write() command sends the binary value 11101010. If the reading is 255, then Serial.write() sends 11111111. If it's 157, then the command sends 10011101. For more decimal-to-binary conversions, open your computer's calculator and choose the Programmer view (press apple-3 on a mac, and Alt-3 on Windows).

When the Serial Monitor receives a byte, it and assumes it should show you the ASCII character corresponding to that byte's value. The garbage characters are characters corresponding to the ASCII values the Monitor is receiving. You'll learn more about that in the second serial lab.

Sending data using write() is efficient for the computer, but it's difficult to read. However, there are other ways to see the serial data. CoolTerm is available for both Mac and Windows. It gives you both an ASCII view of incoming bytes and a hexadecimal view. Download it and install it, and open the Options tab. From there, pick your serial port in the menu, then close the Options tab. Then click the Connect button to open the serial port.

NOTE: only one program can control a serial port at a time. When you're not using a given program, remember to close the serial port. You won't be able to re-program the Arduino module if you don't, because the serial terminal program will have control of the serial port.

Once you have data coming into CoolTerm, click the Hex button. Instead of seeing the ASCII representation of the byte, you'll see its hexadecimal value, with the ASCII characters down the side. As you change the sensor's value, you'll see the values change.

CoolTerm Screenshot
CoolTerm screenshot, showing hex values and ASCII values.

Remember, the microcontroller is just sending a series of electrical pulses. How those pulses are interpreted is up to the program that reads them. In CoolTerm, you see two different interpretations, the hexadecimal value and the ASCII character corresponding to the value.

For most projects, you’ll set the port settings to 9600 bits per second, 8 data bits, no parity, one stop bit, and no hardware flow control. This will be set in the Preferences or Settings or Connection Options of whatever program you're using. Once you’ve applied those settings, open the serial port by clicking. Any bytes you type in the window will be sent out the serial port you opened. They won't show up on the screen, however. Any bytes received in the serial port will be displayed in the window. Click the Disconnect button to close the serial port.


Graph the sensor's values

The serial monitor in Arduino and CoolTerm aren't the only programs on your computer that can read data in from the microcontroller. Any program that can access the computer's serial ports can do it. Processing is an excellent tool for reading serial data because you can program it to interpret the data any way you want. Write a program to take in serial bytes and graph them.

The first thing you need to do is to import the Processing Serial Library. This is a code library that adds functionality to Processing so it can read from and write to the computer's serial ports. You can do this by choosing the Sketch menu, then Import Library...-->serial, or you can type:

import processing.serial.*;

To use the serial library, create an instance of the library in a global variable.

Serial myPort;        // The serial port

Note: you might get an error message when trying to use the Processing Serial Library for the first time. Here are instructions on what to do if this happens.

In the setup() method, set the window size, and use the serial library to get a list of the serial ports:

void setup () {
  size(800, 600);        // window size

  // List all the available serial ports
  println(Serial.list());
}

If you run what you've typed so far, you should get a list of the serial ports in the monitor pane that looks a bit like this on a mac. On a Windows machine, the port list will have names like COM3, COM4, COM5, and so forth:

Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
[0] "/dev/tty.usbserial-A6004osg"
[1] "/dev/cu.usbserial-A6004osg"
[2] "/dev/tty.Bluetooth-Modem"
[3] "/dev/cu.Bluetooth-Modem"
[4] "/dev/tty.Bluetooth-PDA-Sync"
[5] "/dev/cu.Bluetooth-PDA-Sync"
Experimental:  JNI_OnLoad called.

One of these ports is the same as the serial port name you use in the Arduino programming environment. That's the one you want. In the above list, it's port number 0. So to open that port, add the following lines at the end of the setup:

String portName = Serial.list()[0];
myPort = new Serial(this, portName, 9600);

Finally, set the background color. Pick a nice color, don't just use primary colors. You'll be looking at it a long time, so you might as well like it. If you can't think of a nice color combination, try kuler.adobe.com. Add this to the end of the setup:

 background(#081640);

You won't actually do anything in the draw() method for this sketch, but you need it for the program to do anything, so here's an empty draw() method:

void draw () {
  // nothing happens in draw.  It all happens in SerialEvent()
}

The serial library has a special method called serialEvent(). Every time a new byte arrives in the serial port, serialEvent() is called. So you can use it to read bytes from the microcontroller. Write a serialEvent method that reads the incoming byte and prints it out.

void serialEvent (Serial myPort) {
  // get the byte:
  int inByte = myPort.read();
  // print it:
  println(inByte);
}

myPort.read() tells the program to read a byte from the serial port myPort. Bytes are read like peas coming out of a peashooter. Every time you read a byte, it's removed from the serial buffer. So it's good practice to read the byte into a variable as shown above, then never read again until you want another byte. If you want to do something with the byte you read (like graphing it), use the variable you read it into.

Now it's time to draw a graph with the bytes you read. To do this, you'll pick a point whose distance from the bottom of the window corresponds to the byte's value. In other words, the vertical position (call it yPos) equals the height minus the byte's value (@yPos = height - inByte). Add a global variable called xPos and set it to 0. Then, sfter you print out the byte's value in the serialEvent(), set the stroke color to a nice color, and draw a line at xPos, from the bottom of the screen to the vertical position you just calculated.

// at the top of the program:
float xPos = 0;             // horizontal position of the graph

Then add this to serialEvent():

float yPos = height - inByte;
// draw the line in a pretty color:
stroke(#A8D9A7);
line(xPos, height, xPos, height - inByte);

Finally you need to increment the horizontal position after you draw the line, so that the next byte's line is further along on the graph. If you reach the edge of the screen, set the horizontal position back to 0. Do this at the end of the serialEvent.

 // at the edge of the screen, go back to the beginning:
  if (xPos >= width) {
    xPos = 0;
    // clear the screen by resetting the background:
    background(#081640);
  }
  else {
    // increment the horizontal position for the next reading:
    xPos++;
  }

That's it! When you run this sketch, you'll see the sensor's value graphed on the screen like so:

If you get results like the screenshot above, congratulations! You're reading serial data. This would be a good time to stop and review what happened so you're clear on all the details.

This program is worth keeping around for every new analog sensor you work with. It will help you see how the sensor translates physical changes into digital changes. As you can see in the graph above, sometimes a sensor produces a noisy signal. That can interfere with your readings in some cases, so you'd need to filter out the noise. The simplest way to do this is to average the sensor readings over several readings.

This method of serial communication works great if you're only reading one byte at a time repeatedly. However, when you're reading multiple sensors, or sending data back to the microcontroller to control things attached to it, serial communication gets more complex. For more on that, see the second serial lab.

  Edit | View | History | Print | Recent Changes | Search Page last modified on October 01, 2012, at 11:53 AM