(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

Labs.Serial History

Hide minor edits - Show changes to output

Changed lines 1-285 from:
In this lab, you'll send data from sensors to a program on a personal computer.  You'll use the data from the sensors to create a pointing-and-selecting device (i.e. a mouse).


For this lab you'll need:

%lframe width=100px% [[http://itp.nyu.edu/physcomp/images/labs/breadboard.jpg | http://itp.nyu.edu/physcomp/images/labs/breadboard.jpg"Solderless breadboard"]] | [-Solderless breadboard-]
%lframe width=100px% [[http://itp.nyu.edu/physcomp/images/labs/hookup_wire.jpg | http://itp.nyu.edu/physcomp/images/labs/hookup_wire.jpg"hookup wire"]] | [-22-AWG hookup wire-]
%lframe width=100px% [[http://itp.nyu.edu/physcomp/images/labs/arduino.jpg | http://itp.nyu.edu/physcomp/images/labs/arduino.jpg"Arduino module"]] | [-Arduino Microcontroller \\
module-]
[[<<]]

%lframe width=100px valign=center% [[http://itp.nyu.edu/physcomp/images/labs/resistors.jpg | http://itp.nyu.edu/physcomp/images/labs/resistors.jpg"resistors"]] | [-10Kohm resistors-]

%lframe width=90px valign=center% [[http://itp.nyu.edu/physcomp/images/labs/flex_sensors.jpg | http://itp.nyu.edu/physcomp/images/labs/flex_sensors.jpg"flex sensor"]] | [-Flex sensors\\
(or a different\\
 form of variable resistor)-]
%lframe width=100px valign=center% [[http://itp.nyu.edu/physcomp/images/labs/switch.jpg | http://itp.nyu.edu/physcomp/images/labs/switch.jpg"resistors"]] | [-switch-]
[[<<]]

!!! 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:

%alt='Arduino connected to a breadboard' align=top valign=center%http://itp.nyu.edu/physcomp/images/labs/arduino_bboard_power.jpg

If you're using an Arduino breadboard shield, there is a row of sockets connected to 5V on the analog in side of the breadboard, and a row connected to ground on the digital in side of the board:

%alt='Arduino breadboard shield' align=top valign=center%http://itp.nyu.edu/physcomp/images/labs/breadboard_shield.jpg

[[<<]]

!!! Connect the sensors

Connect two analog sensors to analog pins 0 and 1 like you did in the [[Labs/AnalogIn |analog lab]].  Connect a switch to digital pin 2 like you did in the [[Labs/DigitalInOut |digital lab]].

For the photos in this lab, we used a force-sensitive resistor, an infrared ranger, and a pushbutton. The schematic and images are below. Use whatever sensors are appropriate to your final application. Whle you're figuring what sensors to use, use the most convenient sensors you've got in hand; perhaps two pots for the analog sensors and a pushbutton?

(:table:)
(:cellnr colspan=2:)
%height=300 alt='schematic: arduino, 2 analog sensors, 1 switch'%http://itp.nyu.edu/physcomp/images/labs/arduino_2_analog_1_dig_schem.png
(:cellnr:)
Breadboard version
http://itp.nyu.edu/physcomp/images/labs/bboard_3_sensors.JPG
(:cell:)
Breadboard shield version
http://itp.nyu.edu/physcomp/images/labs/bboard_shield_3_sensors.JPG
(:tableend:)

!!! Read and send the serial data

The goal of this section is to understand how the microcontroller formats data when you send it serially.  You'll only use one analog sensor for it.  Program the following into the module:

[@
int analogPin = 0;
int analogValue = 0;            // outgoing ADC value

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
}

void loop()
{
  // read analog input, divide by 4 to make the range 0-255:
  analogValue = analogRead(analogPin);
  analogValue = analogValue / 4;
  Serial.println(analogValue, DEC);
  // pause for 10 milliseconds:
  delay(10);               
}
@]

When you open the Serial Monitor, you should see a number between 0 and 255 scrolling down the debugger pane. That's because the DEC modifier to Serial.println() formats the value it prints as an ASCII-encoded DECimal value. Also, the Serial Monitor assumes it should show you the [[http://www.asciitable.com |ASCII character]] corresponding to each byte it receives.  Try changing the Serial.println like so:

[@ Serial.println(analogValue, BYTE); @]

Now you get a range of garbage characters.  What's going on?  The BYTE modifier doesn't format the bytes. It sends out the raw binary value of the byte.  The Serial Monitor receives that binary value and assumes it should show you the [[http://www.asciitable.com |ASCII character]] corresponding to that value again. The garbage characters are characters correspinding to the ASCII values the Monitor is receiving.

For example, imagine the sensor's value is 128.  Divided by four, it becomes 32.

* @@Serial.println(analogValue, DEC)@@ results in "32"
* @@Serial.println(analogValue, BYTE)@@ results in " ", the space character, which has the ASCII value 32.

Here's the tricky part:  @@Serial.println(analogValue, DEC)@@ actually sent FOUR bytes! It sent a byte to represent the 3, a byte to represent the 2, a byte to tell the Monitor to move the cursor down a line(newline), and a byte to move the cursor all the way to the left (carriage return). The raw binary values of those four bytes are 51 (ASCII for "3"), 50 (ASCII for "2"), 10 (ASCII for "newline), and 13 (ASCII for "carriage return"). Check the [[http://www.asciitable.com |ASCII table]] and you'll see for yourself.

!!! Send the data in many formats

Try this program and view the results in the Serial Monitor:

[@

int analogPin = 0;
int analogValue = 0;                // integer to print

void setup() {
  // open serial communications at 9600 bps
  Serial.begin(9600);
}

void loop() {
  // read the analog inoput, divide by 4:
  analogValue = analogRead(analogPin) /4;

  // print in many formats:
  Serial.print(analogValue, BYTE);    // Print the raw binary value analogValue
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, BIN);      // print the ASCII encoded binary analogValue
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, DEC);      // print the ASCII encoded decimal analogValue
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, HEX);      // print the ASCII encoded hexadecimal analogValue
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, OCT);      // print the ASCII encoded octal analogValue
  Serial.println();                    // print a linefeed and carriage return

  delay(10);
}
@]

You should get output like this:
[@
â 11100010 226 E2 342
á 11100001 225 E1 341
á 11100001 225 E1 341
á 11100001 225 E1 341
à 11100000 224 E0 340
à 11100000 224 E0 340
ß 11011111 223 DF 337
ß 11011111 223 DF 337
ß 11011111 223 DF 337
@]

It's printing the raw binary value, then the ASCII-encoded binary value, then the ASCII-encoded decimal, hexadecimal, and octal values. You may never need all of these differnt formats, but you'll likely need at least the decimal and the raw binary versions at some point.

!!! Send the values for all three sensors

Now send the values for all three sensors as binary values, like so:

[@
int firstSensor = 0;    // first analog sensor
int secondSensor = 0;  // second analog sensor
int thirdSensor = 0;    // digital sensor
int inByte = 0;        // incoming serial byte

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
  pinMode(2, INPUT);  // digital sensor is on digital pin 2
  establishContact();  // send a byte to establish contact until Processing responds
}

void loop()
{
  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    // read first analog input, divide by 4 to make the range 0-255:
    firstSensor = analogRead(0)/4;
    // delay 10ms to let the ADC recover:
    delay(10);
    // read second analog input, divide by 4 to make the range 0-255:
    secondSensor = analogRead(1)/4;
    // read  switch, multiply by 255
    // so that you're sending 100 or 255:
    thirdSensor = 100 + (155 * digitalRead(2));
    // send sensor values:
    Serial.print(firstSensor, BYTE);
    Serial.print(secondSensor, BYTE);
    Serial.print(thirdSensor, BYTE);             
  }
}

void establishContact() {
 while (Serial.available() <= 0) {
      Serial.print('A', BYTE);  // send a capital A
      delay(300);
  }
}


@]

This program will send a single character, "A", then it'll do nothing, because it's then waiting for data to arrive in the serial port before it sends.  To make this work, you'll needto type characters back to the Arduino in the serial monitor.  For every character you type, it'll send you three sensor readings.

You can use other programs besides serial monitor to see the serial communication, as described below:

'''Windows:'''
Hyperterminal can be found in the Start Menu, under All Programs, Accessories, Communications, Hyperterminal.  To configure Hyperterminal for serial communication, open the program and click on the File, Properties menu item.  Choose the serial port you want to open from the popup menu in the Configuration tab. Click on Configure to bring up the Port Settings tab. Set the properties as needed for the device you’re talking to. For many of the projects that follow, you’ll set the port settings to 9600 bits per second, 8 data bits, no parity, one stop bit, and no hardware flow control.  Once you’ve applied those settings, click the Call button on the toolbar to open the serial port. 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.

'''OSX:'''
To configure Terminal for serial communication in OSX, open the program and type @@ls /dev/tty.*@@ This will give you a list of available serial ports. The names of the serial port in OSX are more unique than the names that Windows uses. Pick your serial port and type @@screen portname datarate@@. For example, to open the serial pot on an Arduino board at 9600 bits per second, you might type screen @@/dev/tty.usbserial-5B1 9600@@.  The screen will cleared, and any bytes you type 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. To close the serial port, type control-A followed by control-\. 

'''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've got the serial port open in your terminal program, type any character.  You should get three bytes back, representing the three bytes sent out by the microcontroller. They won't be readable as numbers, though.  If you want to see them as numbers, change BYTE above to DEC in each print statement.

What's happening here is that the computer is calling for a set of sensor readings by sending out a byte.  The Arduino doesn't do anything unless it's received a byte (@@if (Serial.available() > 0)@@).  When it gets a byte, it reads all three sensors and sends them.  This method of communication between computers is called a '''call-and-response''' method, or '''handshaking'''. It's a good way to make sure you get only the data you need, and no more. In the next step, you'll write a Processing program to read those bytes.

!!! Write a program to read those bytes

For this step, you'll need a programming environment that runs on the personal computer itslf, not on the microcontroller. Any environment that can open and close a serial port will do. For example, Java, Processing, Director, RealBASIC, Visual BASIC, and Max/MSP can all access the serial ports. JavaScript and Flash/Actionscript cannot, as of this writing. 

The example below is in Processing. It listens for incoming serial bytes. IF it hasn't gotten any bytes, it looks for "A", which is the first thing that the Arduino sends.  If it's gotten an A, it reads bytes until it gets three of them. Then it sets the foreground color, x position, and y position of a ball on the screen using those values. When there's no incoming bytes available, it sends a byte out to call for more bytes. Read through it line by line, including comments, for the details. Then run it with your Arduino module attached to the serial port it's listening to.

[@

import processing.serial.*;

int bgcolor;     // Background color
int fgcolor;     // Fill color
Serial port;                        // The serial port
int[] serialInArray = new int[3];    // Where we'll put what we receive
int serialCount = 0;                // A count of how many bytes we receive
int xpos, ypos;             // Starting position of the ball
boolean firstContact = false;        // Whether we've heard from the microcontroller

void setup() {
  size(256, 256);  // Stage size
  noStroke();      // No border on the next thing drawn

  // Set the starting position of the ball (middle of the stage)
  xpos = width/2;
  ypos = height/2;

  // Print a list of the serial ports, for debugging purposes:
  println(Serial.list());

  // I know that the first port in the serial list on my mac
  // is always my  Keyspan adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  port = new Serial(this, Serial.list()[0], 9600);
}

void draw() {
  background(bgcolor);
  fill(fgcolor);
  // Draw the shape
  ellipse(xpos, ypos, 20, 20);
}

void serialEvent(Serial port) {
  // read a byte from the serial port:
  int inByte = port.read();
  // if this is the first byte received,
  // take note of that fact. Otherwise, add it to the array:
  if (firstContact == false) {
    if (inByte == 'A') {
      port.clear();          // clear the serial port buffer
      firstContact = true;
      port.write('A');
    }
  }
  else {
    // Add the latest byte from the serial port to array:
    serialInArray[serialCount] = inByte;
    serialCount++;

    // If we have 3 bytes:
    if (serialCount > 2 ) {
      xpos = serialInArray[0];
      ypos = serialInArray[1];
      fgcolor = serialInArray[2];

      // print the values (for debugging purposes only):
      println(xpos + "\t" + ypos + "\t" + fgcolor);

      // Send a capital A to request new sensor readings:
      port.write('A');
      // Reset serialCount:
      serialCount = 0;
    }
  }
}


@]

If you did everything right, the ball should move in response to the analog sensors, and appear or disappear when you press the button.

!!! Get creative

You just duplicated the basic functionality of a mouse; that is, a device with two analog sensors that affect X and Y, and a digital sensor (mouse button).  What applications can you think of that could use a better physical interface for a mouse?  Create a prototype in Arduino and Processing, or whatever programming environment you choose.  Come up with a physical interface that makes it clear what actions map to what movements and actions. Figure out which actions can and should be possible at the same time (e.g. moving x and y to make a diagonal path). Think about what actions should be exclusive, if any (e.g. pressing two mouse buttons at once?).  Present a working software and hardware model of your idea.
to:
* [[Labs/SerialOut| First serial lab]]
* [[Labs/SerialDuplex| Second serial lab]]
Deleted lines 241-248:

  // If no serial data has beeen received, send again until we get some.
  // (in case you tend to start Processing before you start your
  // external device):
  if (firstContact == false) {
    delay(300);
    port.write(65);
  }
Added line 253:
     port.write('A');
Changed line 271 from:
     port.write(65);
to:
     port.write('A');
Changed line 150 from:
  establishContact()   // send a byte to establish contact until Processing responds
to:
  establishContact();  // send a byte to establish contact until Processing responds
Changed line 150 from:
  Serial.print("A");  // print an A to say the program is running
to:
  establishContact()  // send a byte to establish contact until Processing responds
Changed lines 166-167 from:
   // so that you're sending 0 or 255:
    thirdSensor = 255 * digitalRead(2);
to:
   // so that you're sending 100 or 255:
    thirdSensor = 100 + (155 * digitalRead(2));
Changed lines 175-182 from:
to:
void establishContact() {
 while (Serial.available() <= 0) {
      Serial.print('A', BYTE);  // send a capital A
      delay(300);
  }
}

Changed line 216 from:
int xpos, ypos;     // Starting position of the ball
to:
int xpos, ypos;            // Starting position of the ball
Added line 259:
     port.clear();          // clear the serial port buffer
Added line 150:
  Serial.print("A");  // print an A to say the program is running
Added lines 174-175:

Changed lines 178-179 from:
This isn't going to do anything in the Serial Monitor, because it's waiting for a byte from the computer before it sends.  To make this work, you'll need a serial monitor that allows you to send bytes as well as to receive them. In Windows, you can use Hyperterminal. In OSX, you can use the Terminal program.
to:
This program will send a single character, "A", then it'll do nothing, because it's then waiting for data to arrive in the serial port before it sends.  To make this work, you'll needto type characters back to the Arduino in the serial monitor.  For every character you type, it'll send you three sensor readings.

You can use other programs besides serial monitor to see the serial communication, as described below:

Changed lines 198-199 from:
The example below is in Processing. It listens for incoming serial bytes until it gets three of them. Then it sets the foreground color, x position, and y position of a ball on the screen using those values. When there's no incoming bytes available, it sends a byte out to call for more bytes. Read through it line by line, including comments, for the details. Then run it with your Arduino module attached to the serial port it's listening to.
to:
The example below is in Processing. It listens for incoming serial bytes. IF it hasn't gotten any bytes, it looks for "A", which is the first thing that the Arduino sends.  If it's gotten an A, it reads bytes until it gets three of them. Then it sets the foreground color, x position, and y position of a ball on the screen using those values. When there's no incoming bytes available, it sends a byte out to call for more bytes. Read through it line by line, including comments, for the details. Then run it with your Arduino module attached to the serial port it's listening to.
Deleted line 227:
  port.write(65);    // Send a capital A to start the microcontroller sending
Added lines 246-247:
  // read a byte from the serial port:
  int inByte = port.read();
Changed line 249 from:
  // take note of that fact:
to:
  // take note of that fact. Otherwise, add it to the array:
Changed lines 251-273 from:
   firstContact = true;
to:
   if (inByte == 'A') {
      firstContact = true;
    }
  }
  else {
    // Add the latest byte from the serial port to array:
    serialInArray[serialCount] = inByte;
    serialCount++;

    // If we have 3 bytes:
    if (serialCount > 2 ) {
      xpos = serialInArray[0];
      ypos = serialInArray[1];
      fgcolor = serialInArray[2];

      // print the values (for debugging purposes only):
      println(xpos + "\t" + ypos + "\t" + fgcolor);

      // Send a capital A to request new sensor readings:
      port.write(65);
      // Reset serialCount:
      serialCount = 0;
    }
Deleted lines 274-291:
  // Add the latest byte from the serial port to array:
  serialInArray[serialCount] = port.read();
  serialCount++;

  // If we have 3 bytes:
  if (serialCount > 2 ) {
    xpos = serialInArray[0];
    ypos = serialInArray[1];
    fgcolor = serialInArray[2];

    // print the values (for debugging purposes only):
    println(xpos + "\t" + ypos + "\t" + fgcolor);

    // Send a capital A to request new sensor readings:
    port.write(65);
    // Reset serialCount:
    serialCount = 0;
  }
Added line 277:
Changed line 149 from:
  pinMode(thirdSensor, INPUT);
to:
  pinMode(2, INPUT);   // digital sensor is on digital pin 2
October 07, 2007, at 04:43 PM by 151.202.68.246 -
Changed lines 73-74 from:
When you open the Serial Monitor, you should see a number between 0 and 255 scrolling down the debugger pane. That's because the DEC modifier to Serial.println() formats the value it prints as an ASCII-encoded DECimal value. Also, the Serial Monitor assumes it should show you the [[http://www,asciitable.com |ASCII character]] corresponding to each byte it receives.  Try changing the Serial.println like so:
to:
When you open the Serial Monitor, you should see a number between 0 and 255 scrolling down the debugger pane. That's because the DEC modifier to Serial.println() formats the value it prints as an ASCII-encoded DECimal value. Also, the Serial Monitor assumes it should show you the [[http://www.asciitable.com |ASCII character]] corresponding to each byte it receives.  Try changing the Serial.println like so:
Changed lines 77-78 from:
Now you get a range of garbage characters.  What's going on?  The BYTE modifier doesn't format the bytes. It sends out the raw binary value of the byte.  The Serial Monitor receives that binary value and assumes it should show you the [[http://www,asciitable.com |ASCII character]] corresponding to that value again. The garbage characters are characters correspinding to the ASCII values the Monitor is receiving.
to:
Now you get a range of garbage characters.  What's going on?  The BYTE modifier doesn't format the bytes. It sends out the raw binary value of the byte.  The Serial Monitor receives that binary value and assumes it should show you the [[http://www.asciitable.com |ASCII character]] corresponding to that value again. The garbage characters are characters correspinding to the ASCII values the Monitor is receiving.
Changed lines 84-85 from:
Here's the tricky part:  @@Serial.println(analogValue, DEC)@@ actually sent FOUR bytes! It sent a byte to represent the 3, a byte to represent the 2, a byte to tell the Monitor to move the cursor down a line(newline), and a byte to move the cursor all the way to the left (carriage return). The raw binary values of those four bytes are 51 (ASCII for "3"), 50 (ASCII for "2"), 10 (ASCII for "newline), and 13 (ASCII for "carriage return"). Check the [[http://www,asciitable.com |ASCII table]] and you'll see for yourself.
to:
Here's the tricky part:  @@Serial.println(analogValue, DEC)@@ actually sent FOUR bytes! It sent a byte to represent the 3, a byte to represent the 2, a byte to tell the Monitor to move the cursor down a line(newline), and a byte to move the cursor all the way to the left (carriage return). The raw binary values of those four bytes are 51 (ASCII for "3"), 50 (ASCII for "2"), 10 (ASCII for "newline), and 13 (ASCII for "carriage return"). Check the [[http://www.asciitable.com |ASCII table]] and you'll see for yourself.
Added line 149:
  pinMode(thirdSensor, INPUT);
Added line 41:
Breadboard version
Added line 44:
Breadboard shield version
Changed lines 35-36 from:
For the photos in this lab, we used a force-sensitive resistor, an infrared ranger, and a pushbutton. The schematic and images are below. Use whatever seems appropriate to your final application.
to:
For the photos in this lab, we used a force-sensitive resistor, an infrared ranger, and a pushbutton. The schematic and images are below. Use whatever sensors are appropriate to your final application. Whle you're figuring what sensors to use, use the most convenient sensors you've got in hand; perhaps two pots for the analog sensors and a pushbutton?
Changed lines 37-39 from:
%height=240 alt='schematic: arduino, 2 analog sensors, 1 switch'%http://itp.nyu.edu/physcomp/images/labs/arduino_2_analog_1_dig_schem.png

to:
(:table:)
(:cellnr colspan=
2:)
%height=300 alt='schematic: arduino
, 2 analog sensors, 1 switch'%http://itp.nyu.edu/physcomp/images/labs/arduino_2_analog_1_dig_schem.png
(:cellnr:)
http://itp.nyu.edu/physcomp/images/labs/bboard_3_sensors.JPG
(:cell:)
http://itp.nyu.edu/physcomp/images/labs/bboard_shield_3_sensors.JPG
(:tableend:)

Changed lines 35-36 from:
For the photos in this lab, we used a force-sensitive resistor, an infrared ranger, and a pushbutton. Use whatever seems appropriate to your final application.
to:
For the photos in this lab, we used a force-sensitive resistor, an infrared ranger, and a pushbutton. The schematic and images are below. Use whatever seems appropriate to your final application.

%height=240 alt='schematic: arduino, 2 analog sensors, 1 switch'%http://itp.nyu.edu/physcomp/images/labs/arduino_2_analog_1_dig_schem.png


Added lines 257-261:
If you did everything right, the ball should move in response to the analog sensors, and appear or disappear when you press the button.

!!! Get creative

You just duplicated the basic functionality of a mouse; that is, a device with two analog sensors that affect X and Y, and a digital sensor (mouse button).  What applications can you think of that could use a better physical interface for a mouse?  Create a prototype in Arduino and Processing, or whatever programming environment you choose.  Come up with a physical interface that makes it clear what actions map to what movements and actions. Figure out which actions can and should be possible at the same time (e.g. moving x and y to make a diagonal path). Think about what actions should be exclusive, if any (e.g. pressing two mouse buttons at once?).  Present a working software and hardware model of your idea.
Changed lines 181-182 from:
The example below is in Processing. It listens for incoming serial bytes until it gets three of them. Then it sets the foreground color, x position, and y position of a ball on the screen using those values. When there's no incoming bytes available, it sends a byte out to call for more bytes.
to:
The example below is in Processing. It listens for incoming serial bytes until it gets three of them. Then it sets the foreground color, x position, and y position of a ball on the screen using those values. When there's no incoming bytes available, it sends a byte out to call for more bytes. Read through it line by line, including comments, for the details. Then run it with your Arduino module attached to the serial port it's listening to.
Changed line 148 from:
   // delay 10ms so the analog-to-digital converter can reset:
to:
   // delay 10ms to let the ADC recover:
Changed lines 152-153 from:
   // read  switch:
    thirdSensor = digitalRead(2)
/4;
to:
   // read  switch, multiply by 255
 
   // so that you're sending 0 or 255:
    thirdSensor = 255 * digitalRead(2)
;
Changed lines 179-182 from:
For this step, you'll need a programming environment that runs on the personal computer itslf, not on the microcontroller. Any environment that can open and close a serial port will do. For example, Java, Processing, Director, RealBASIC, Visual BASIC, and Max/MSP can all access the serial ports. JavaScript and Flash/Actionscript cannot, as of this writing.  The example below is all in Processing.


to:
For this step, you'll need a programming environment that runs on the personal computer itslf, not on the microcontroller. Any environment that can open and close a serial port will do. For example, Java, Processing, Director, RealBASIC, Visual BASIC, and Max/MSP can all access the serial ports. JavaScript and Flash/Actionscript cannot, as of this writing. 

The example below is in Processing. It listens for incoming serial bytes until it gets three of them. Then it sets the foreground color, x position, and y position of a ball on the screen using those values. When there's no incoming bytes available, it sends a byte out to call for more bytes.

[@

import processing.serial.*;

int bgcolor;     // Background color
int fgcolor;     // Fill color
Serial port;                        // The serial port
int[] serialInArray = new int[3];    // Where we'll put what we receive
int serialCount = 0;                // A count of how many bytes we receive
int xpos, ypos;     // Starting position of the ball
boolean firstContact = false;        // Whether we've heard from the microcontroller

void setup() {
  size(256, 256);  // Stage size
  noStroke();      // No border on the next thing drawn

  // Set the starting position of the ball (middle of the stage)
  xpos = width/2;
  ypos = height/2;

  // Print a list of the serial ports, for debugging purposes:
  println(Serial.list());

  // I know that the first port in the serial list on my mac
  // is always my  Keyspan adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  port = new Serial(this, Serial.list()[0], 9600);
  port.write(65);    // Send a capital A to start the microcontroller sending
}

void draw() {
  background(bgcolor);
  fill(fgcolor);
  // Draw the shape
  ellipse(xpos, ypos, 20, 20);

  // If no serial data has beeen received, send again until we get some.
  // (in case you tend to start Processing before you start your
  // external device):
  if (firstContact == false) {
    delay(300);
    port.write(65);
  }
}

void serialEvent(Serial port) {
  // if this is the first byte received,
  // take note of that fact:
  if (firstContact == false) {
    firstContact = true;
  }
  // Add the latest byte from the serial port to array:
  serialInArray[serialCount] = port.read();
  serialCount++;

  // If we have 3 bytes:
  if (serialCount > 2 ) {
    xpos = serialInArray[0];
    ypos = serialInArray[1];
    fgcolor = serialInArray[2];

    // print the values (for debugging purposes only):
    println(xpos + "\t" + ypos + "\t" + fgcolor);

    // Send a capital A to request new sensor readings:
    port.write(65);
    // Reset serialCount:
    serialCount = 0;
  }
}

@]

Added lines 148-149:
   // delay 10ms so the analog-to-digital converter can reset:
    delay(10);
Changed line 151 from:
   secondSensor = analogRead(0)/4;
to:
   secondSensor = analogRead(1)/4;
Added lines 174-179:
!!! Write a program to read those bytes

For this step, you'll need a programming environment that runs on the personal computer itslf, not on the microcontroller. Any environment that can open and close a serial port will do. For example, Java, Processing, Director, RealBASIC, Visual BASIC, and Max/MSP can all access the serial ports. JavaScript and Flash/Actionscript cannot, as of this writing.  The example below is all in Processing.


Changed lines 166-167 from:
To configure Terminal for serial communication in OSX, open the program and type @@@ls /dev/tty.*@@@ This will give you a list of available serial ports. The names of the serial port in OSX are more unique than the names that Windows uses. Pick your serial port and type @@@screen portname datarate@@@. For example, to open the serial pot on an Arduino board at 9600 bits per second, you might type screen @@@/dev/tty.usbserial-5B1 9600@@@.  The screen will cleared, and any bytes you type 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. To close the serial port, type control-A followed by control-\. 
to:
To configure Terminal for serial communication in OSX, open the program and type @@ls /dev/tty.*@@ This will give you a list of available serial ports. The names of the serial port in OSX are more unique than the names that Windows uses. Pick your serial port and type @@screen portname datarate@@. For example, to open the serial pot on an Arduino board at 9600 bits per second, you might type screen @@/dev/tty.usbserial-5B1 9600@@.  The screen will cleared, and any bytes you type 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. To close the serial port, type control-A followed by control-\. 
Changed lines 172-173 from:
What's happening here is that the computer is calling for a set of sensor readings by sending out a byte.  The Arduino doesn't do anything unless it's received a byte (@@@if (Serial.available() > 0)@@@).  When it gets a byte, it reads all three sensors and sends them.  This method of communication between computers is called a '''call-and-response''' method, or '''handshaking'''. It's a good way to make sure you get only the data you need, and no more. In the next step, you'll write a Processing program to read those bytes.
to:
What's happening here is that the computer is calling for a set of sensor readings by sending out a byte.  The Arduino doesn't do anything unless it's received a byte (@@if (Serial.available() > 0)@@).  When it gets a byte, it reads all three sensors and sends them.  This method of communication between computers is called a '''call-and-response''' method, or '''handshaking'''. It's a good way to make sure you get only the data you need, and no more. In the next step, you'll write a Processing program to read those bytes.
Changed lines 170-173 from:
Once you've got the serial port open in your terminal program, type any character.  You should get three bytes back, representing the three bytes sent out by the microcontroller.
to:
Once you've got the serial port open in your terminal program, type any character.  You should get three bytes back, representing the three bytes sent out by the microcontroller. They won't be readable as numbers, though.  If you want to see them as numbers, change BYTE above to DEC in each print statement.

What's happening here is that the computer is calling for a set of sensor readings by sending out a byte.  The Arduino doesn't do anything unless it's received a byte (@@@if (Serial.available() > 0)@@@).  When it gets a byte, it reads all three sensors and sends them.  This method of communication between computers is called a '''call-and-response''' method, or '''handshaking'''. It's a good way to make sure you get only the data you need, and no more. In the next step, you'll write a Processing program to read those bytes.

Added lines 168-170:
'''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've got the serial port open in your terminal program, type any character.  You should get three bytes back, representing the three bytes sent out by the microcontroller.
Changed lines 160-167 from:
This isn't going to do anything in the Serial Monitor, because it's waiting for a byte from the computer before it sends.  To make this work, you'll need a serial monitor that allows you to send bytes as well as to receive them. In Windows, you can use Hyperterminal. In OSX, you can use the Terminal program.
to:
This isn't going to do anything in the Serial Monitor, because it's waiting for a byte from the computer before it sends.  To make this work, you'll need a serial monitor that allows you to send bytes as well as to receive them. In Windows, you can use Hyperterminal. In OSX, you can use the Terminal program.

'''Windows:'''
Hyperterminal can be found in the Start Menu, under All Programs, Accessories, Communications, Hyperterminal.  To configure Hyperterminal for serial communication, open the program and click on the File, Properties menu item.  Choose the serial port you want to open from the popup menu in the Configuration tab. Click on Configure to bring up the Port Settings tab. Set the properties as needed for the device you’re talking to. For many of the projects that follow, you’ll set the port settings to 9600 bits per second, 8 data bits, no parity, one stop bit, and no hardware flow control.  Once you’ve applied those settings, click the Call button on the toolbar to open the serial port. 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.

'''OSX:'''
To configure Terminal for serial communication in OSX, open the program and type @@@ls /dev/tty.*@@@ This will give you a list of available serial ports. The names of the serial port in OSX are more unique than the names that Windows uses. Pick your serial port and type @@@screen portname datarate@@@. For example, to open the serial pot on an Arduino board at 9600 bits per second, you might type screen @@@/dev/tty.usbserial-5B1 9600@@@.  The screen will cleared, and any bytes you type 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. To close the serial port, type control-A followed by control-\. 

Changed lines 129-157 from:
to:
int firstSensor = 0;    // first analog sensor
int secondSensor = 0;  // second analog sensor
int thirdSensor = 0;    // digital sensor
int inByte = 0;        // incoming serial byte

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
}

void loop()
{
  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    // read first analog input, divide by 4 to make the range 0-255:
    firstSensor = analogRead(0)/4;
    // read second analog input, divide by 4 to make the range 0-255:
    secondSensor = analogRead(0)/4;
    // read  switch:
    thirdSensor = digitalRead(2)/4;
    // send sensor values:
    Serial.print(firstSensor, BYTE);
    Serial.print(secondSensor, BYTE);
    Serial.print(thirdSensor, BYTE);             
  }
}
Added line 160:
This isn't going to do anything in the Serial Monitor, because it's waiting for a byte from the computer before it sends.  To make this work, you'll need a serial monitor that allows you to send bytes as well as to receive them. In Windows, you can use Hyperterminal. In OSX, you can use the Terminal program.
Changed lines 120-132 from:
@]
to:
@]

It's printing the raw binary value, then the ASCII-encoded binary value, then the ASCII-encoded decimal, hexadecimal, and octal values. You may never need all of these differnt formats, but you'll likely need at least the decimal and the raw binary versions at some point.

!!! Send the values for all three sensors

Now send the values for all three sensors as binary values, like so:

[@

@]

 
Deleted lines 105-106:

Added lines 107-119:
@]

You should get output like this:
[@
â 11100010 226 E2 342
á 11100001 225 E1 341
á 11100001 225 E1 341
á 11100001 225 E1 341
à 11100000 224 E0 340
à 11100000 224 E0 340
ß 11011111 223 DF 337
ß 11011111 223 DF 337
ß 11011111 223 DF 337
Changed line 94 from:
  Serial.print(analogValue, BYTE);    // Print the raw binary value 65
to:
  Serial.print(analogValue, BYTE);    // Print the raw binary value analogValue
Changed line 96 from:
  Serial.print(analogValue, BIN);      // print the ASCII encoded binary 65
to:
  Serial.print(analogValue, BIN);      // print the ASCII encoded binary analogValue
Changed line 98 from:
  Serial.print(analogValue, DEC);      // print the ASCII encoded decimal 65
to:
  Serial.print(analogValue, DEC);      // print the ASCII encoded decimal analogValue
Changed line 100 from:
  Serial.print(analogValue, HEX);      // print the ASCII encoded hexadecimal 65
to:
  Serial.print(analogValue, HEX);      // print the ASCII encoded hexadecimal analogValue
Changed line 102 from:
  Serial.print(analogValue, OCT);      // print the ASCII encoded octal 65
to:
  Serial.print(analogValue, OCT);      // print the ASCII encoded octal analogValue
Changed lines 73-109 from:
Here's the tricky part:  @@Serial.println(analogValue, DEC)@@ actually sent FOUR bytes! It sent a byte to represent the 3, a byte to represent the 2, a byte to tell the Monitor to move the cursor down a line(newline), and a byte to move the cursor all the way to the left (carriage return). The raw binary values of those four bytes are 51 (ASCII for "3"), 50 (ASCII for "2"), 10 (ASCII for "newline), and 13 (ASCII for "carriage return"). Check the [[http://www,asciitable.com |ASCII table]] and you'll see for yourself.
to:
Here's the tricky part:  @@Serial.println(analogValue, DEC)@@ actually sent FOUR bytes! It sent a byte to represent the 3, a byte to represent the 2, a byte to tell the Monitor to move the cursor down a line(newline), and a byte to move the cursor all the way to the left (carriage return). The raw binary values of those four bytes are 51 (ASCII for "3"), 50 (ASCII for "2"), 10 (ASCII for "newline), and 13 (ASCII for "carriage return"). Check the [[http://www,asciitable.com |ASCII table]] and you'll see for yourself.

!!! Send the data in many formats

Try this program and view the results in the Serial Monitor:

[@

int analogPin = 0;
int analogValue = 0;                // integer to print

void setup() {
  // open serial communications at 9600 bps
  Serial.begin(9600);
}

void loop() {
  // read the analog inoput, divide by 4:
  analogValue = analogRead(analogPin) /4;

  // print in many formats:
  Serial.print(analogValue, BYTE);    // Print the raw binary value 65
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, BIN);      // print the ASCII encoded binary 65
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, DEC);      // print the ASCII encoded decimal 65
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, HEX);      // print the ASCII encoded hexadecimal 65
  Serial.print('\t');                  // print a tab
  Serial.print(analogValue, OCT);      // print the ASCII encoded octal 65
  Serial.println();                    // print a linefeed and carriage return

  delay(10);


}
@]
Changed lines 66-67 from:
Now you get a range of garbage characters.  What's going on?  The BYTE modifier doesn't format the bytes. It sends out the raw binary value of the byte.  The Serial Monitor receives that binary value and assumes it should show you the [[http://www,asciitable.com |ASCII charcter]] corresponding to that value again. The garbage characters are characters correspinding to the ASCII values the Monitor is receiving.
to:
Now you get a range of garbage characters.  What's going on?  The BYTE modifier doesn't format the bytes. It sends out the raw binary value of the byte.  The Serial Monitor receives that binary value and assumes it should show you the [[http://www,asciitable.com |ASCII character]] corresponding to that value again. The garbage characters are characters correspinding to the ASCII values the Monitor is receiving.
Changed lines 33-73 from:
Connect two analog sensors to analog pins 0 and 1 like you did in the [[Labs/AnalogIn |analog lab]].  Connect a switch to digital pin 2 like you did in the [[Labs/DigitalInOut |digital lab]].
to:
Connect two analog sensors to analog pins 0 and 1 like you did in the [[Labs/AnalogIn |analog lab]].  Connect a switch to digital pin 2 like you did in the [[Labs/DigitalInOut |digital lab]].

For the photos in this lab, we used a force-sensitive resistor, an infrared ranger, and a pushbutton. Use whatever seems appropriate to your final application.

!!! Read and send the serial data

The goal of this section is to understand how the microcontroller formats data when you send it serially.  You'll only use one analog sensor for it.  Program the following into the module:

[@
int analogPin = 0;
int analogValue = 0;            // outgoing ADC value

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
}

void loop()
{
  // read analog input, divide by 4 to make the range 0-255:
  analogValue = analogRead(analogPin);
  analogValue = analogValue / 4;
  Serial.println(analogValue, DEC);
  // pause for 10 milliseconds:
  delay(10);               
}
@]

When you open the Serial Monitor, you should see a number between 0 and 255 scrolling down the debugger pane. That's because the DEC modifier to Serial.println() formats the value it prints as an ASCII-encoded DECimal value. Also, the Serial Monitor assumes it should show you the [[http://www,asciitable.com |ASCII character]] corresponding to each byte it receives.  Try changing the Serial.println like so:

[@ Serial.println(analogValue, BYTE); @]

Now you get a range of garbage characters.  What's going on?  The BYTE modifier doesn't format the bytes. It sends out the raw binary value of the byte.  The Serial Monitor receives that binary value and assumes it should show you the [[http://www,asciitable.com |ASCII charcter]] corresponding to that value again. The garbage characters are characters correspinding to the ASCII values the Monitor is receiving.

For example, imagine the sensor's value is 128.  Divided by four, it becomes 32.

* @@Serial.println(analogValue, DEC)@@ results in "32"
* @@Serial.println(analogValue, BYTE)@@ results in " ", the space character, which has the ASCII value 32.

Here's the tricky part:  @@Serial.println(analogValue, DEC)@@ actually sent FOUR bytes! It sent a byte to represent the 3, a byte to represent the 2, a byte to tell the Monitor to move the cursor down a line(newline), and a byte to move the cursor all the way to the left (carriage return). The raw binary values of those four bytes are 51 (ASCII for "3"), 50 (ASCII for "2"), 10 (ASCII for "newline), and 13 (ASCII for "carriage return"). Check the [[http://www,asciitable.com |ASCII table]] and you'll see for yourself.
Added line 17:
%lframe width=100px valign=center% [[http://itp.nyu.edu/physcomp/images/labs/switch.jpg | http://itp.nyu.edu/physcomp/images/labs/switch.jpg"resistors"]] | [-switch-]
Changed line 33 from:
Connect two analog sensors to analog pins 0 and 1 like you did in the analog lab.  Connect a switch to digital pin 2 like you did in the digital lab.
to:
Connect two analog sensors to analog pins 0 and 1 like you did in the [[Labs/AnalogIn |analog lab]].  Connect a switch to digital pin 2 like you did in the [[Labs/DigitalInOut |digital lab]].
Added lines 1-32:
In this lab, you'll send data from sensors to a program on a personal computer.  You'll use the data from the sensors to create a pointing-and-selecting device (i.e. a mouse).


For this lab you'll need:

%lframe width=100px% [[http://itp.nyu.edu/physcomp/images/labs/breadboard.jpg | http://itp.nyu.edu/physcomp/images/labs/breadboard.jpg"Solderless breadboard"]] | [-Solderless breadboard-]
%lframe width=100px% [[http://itp.nyu.edu/physcomp/images/labs/hookup_wire.jpg | http://itp.nyu.edu/physcomp/images/labs/hookup_wire.jpg"hookup wire"]] | [-22-AWG hookup wire-]
%lframe width=100px% [[http://itp.nyu.edu/physcomp/images/labs/arduino.jpg | http://itp.nyu.edu/physcomp/images/labs/arduino.jpg"Arduino module"]] | [-Arduino Microcontroller \\
module-]
[[<<]]

%lframe width=100px valign=center% [[http://itp.nyu.edu/physcomp/images/labs/resistors.jpg | http://itp.nyu.edu/physcomp/images/labs/resistors.jpg"resistors"]] | [-10Kohm resistors-]

%lframe width=90px valign=center% [[http://itp.nyu.edu/physcomp/images/labs/flex_sensors.jpg | http://itp.nyu.edu/physcomp/images/labs/flex_sensors.jpg"flex sensor"]] | [-Flex sensors\\
(or a different\\
 form of variable resistor)-]
[[<<]]

!!! 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:

%alt='Arduino connected to a breadboard' align=top valign=center%http://itp.nyu.edu/physcomp/images/labs/arduino_bboard_power.jpg

If you're using an Arduino breadboard shield, there is a row of sockets connected to 5V on the analog in side of the breadboard, and a row connected to ground on the digital in side of the board:

%alt='Arduino breadboard shield' align=top valign=center%http://itp.nyu.edu/physcomp/images/labs/breadboard_shield.jpg

[[<<]]

!!! Connect the sensors

Connect two analog sensors to analog pins 0 and 1 like you did in the analog lab.  Connect a switch to digital pin 2 like you did in the digital lab.
  Edit | View | History | Print | Recent Changes | Search Page last modified on August 25, 2008, at 02:31 PM