|
Research & Learning Class pages
Shop Admin
ITP Help Pages |
Igoe ClassThis is a place for class notes and discussion from Tom's Intro phys comp classes, Fall 2007. If you're in the class, you can edit it. -- Class blogs: Morning Section:
Afternoon Section:
10/31/07Simple Serial Input to Arduino:
/*
Simple Serial Input
Listens for serial input.
ASCII A turns on an LED on pin 10
ASCII B turns on an LED on pin 11
Any other value turns LEDs off.
*/
void setup() {
// initialize serial:
Serial.begin(9600);
// initialize digital I/O pins:
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
}
void loop() {
// if there's any incoming serial bytes:
if (Serial.available() > 0) {
// read the first byte received:
int inByte = Serial.read();
// check its value:
switch (inByte) {
// if inByte is ASCII A:
case 'A':
digitalWrite(10, HIGH);
break;
//if inByte is ASCII B:
case 'B':
digitalWrite(11, HIGH);
break;
// if inByte is any other value:
default:
digitalWrite(10, LOW);
digitalWrite(11, LOW);
}
}
}
XBee Serial TerminalThis is a Processing application that's useful for communicating with XBee radios. Since the Xbee radio's response strings end in a return character (ASCII 13) but no newline (ASCII 10), reading their responses can be a pain in a serial terminal program like screen or HyperTerminal. This Processing sketch adds a newline after each return it sees, to make the Xbee's responses more readable. 10/3/07Call-and-Response Method for Sending Three Bytes Serially to ArduinoFor the morning class, here's why the Processing call-and-response app didn't work. First, here's the non-working code as we left class:
import processing.serial.*;
Serial myPort; // serial port
int[] sensorValues = new int[3]; // array for incoming sensor values
int i = 0; // array counter
void setup() {
// set the window size and turn smoothing on:
size(400,300);
smooth();
// list all serial ports
println(Serial.list());
// pick the first port (which happens to be our Arduino port):
String portName = Serial.list()[0];
// open the serial port in a new instance of the serial class
myPort = new Serial(this, portName, 9600);
// send an initial byte to ask for data from the Arduino:
myPort.write("A");
println("A");
}
void draw() {
// clear the screen:
background(0);
// set the fill color based on a sensor value:
fill(sensorValues[2]);
// draw the circle. Position depends on the sensor values:
ellipse(sensorValues[0], sensorValues[1], 20, 20);
}
void serialEvent(Serial myPort) {
// read a byte into the sensor value array:
sensorValues[i] = myPort.read();
// increment the array counter:
i++;
// if you've got three bytes, reset the array counter
// and ask the Arduino for more bytes:
if (i > 2) {
i =0;
myPort.write("A");
println("A");
println(sensorValues[i]);
}
}
Now, you may recall that we saw Processing send the initial "A" to ask for data, but got nothing back. The problem was that the Arduino wasn't listening when that byte was sent. The usual reason for this is because the Arduino has been reset and hasn't yet started its program. This is particularly common with the Arduino Diecimila, because it resets whenever you open the serial port on a Mac.However, it's not limited to the Arduino. Because the communication is asynchronous, it's possible (and even pretty likely) that one computer may not be listening when the other sends. I've seen this time and time again with different microcontrollers. The solution to this is for Processing to keep asking for bytes until it gets some. You can see this in the final piece of Processing code in the serial lab exercise. That program has a variable called firstContact. When the program starts, firstContact is false, meaning that Processing hasn't yet received a first set of bytes from the Arduino. So in the draw loop, there's an if statement that checks to see if first contact has been made, and if not, it continually asks for more, with a little pause in between. It's as if you're nudging the Arduino gently until it responds, like so:
if (firstContact == false) {
myPort.write("A");
println("A");
delay(300);
}
When the first byte comes in from the Arduino, you set firstContact to be true, and the program proceeds as it should, continually calling for more data when there is none, and responding to what comes in. Here's an adjusted version of what we wrote in class, but this version works, just like the lab version:
import processing.serial.*;
Serial myPort; // serial port
int[] sensorValues = new int[3]; // array for incoming sensor values
int i = 0; // array counter
boolean firstContact = false; // whether or not you've gotten any bytes at all
void setup() {
// set hte window size and turn smoothing on:
size(400,300);
smooth();
// list all serial ports
println(Serial.list());
// pick the first port (which happens to be our Arduino port):
String portName = Serial.list()[0];
// open the serial port in a new instance of the serial class
myPort = new Serial(this, portName, 9600);
// send an initial byte to ask for data from the Arduino:
myPort.write("A");
println("A");
}
void draw() {
// clear the screen:
background(0);
// set the fill color based on a sensor value:
fill(sensorValues[2]);
// draw the circle. Position depends on the sensor values:
ellipse(sensorValues[0], sensorValues[1], 20, 20);
// check to see if you've gotten an initial byte from the Arduino,
// and ask for it if you haven't:
if (firstContact == false) {
myPort.write("A");
println("A");
delay(300);
}
}
void serialEvent(Serial myPort) {
// if serialEvent is called, that means you've gotten at least one
// byte. Take not of this so that you can stop checking for first contact
// in the main loop:
firstContact = true;
// read a byte into the sensor value array:
sensorValues[i] = myPort.read();
// increment the array counter:
i++;
// if you've got three bytes, reset the array counter
// and ask the Arduino for more bytes:
if (i > 2) {
i =0;
myPort.write("A");
println("A");
println(sensorValues[i]);
}
}
Here's the Arduino code for this example:
/*
Multi-byte serial example using call-and-response
Language: Arduino
This example waits for an incoming byte, then sends a three-byte "sentence"
of sensor readings from a microcontroller.
The sensor readings can range from 0 - 255.
Created 3 Oct. 2007
by Tom Igoe
*/
int sensor[3]; // array to hold the sensor values
void setup() {
// initialize the serial port:
Serial.begin(9600);
}
void loop() {
// for loop to count from 0 to 2:
for (int i = 0; i < 3; i++) {
// read one of the sensors, divide by 4, put into the array:
sensor[i] = analogRead(i)/4;
// if the value is 255, truncate it so we can use 255
// as a unique value to punctuate the sentence:
if (sensor[i] == 255) {
sensor[i] = 254;
}
// print the current sensor value:
Serial.print(sensor[i], BYTE);
}
// After printing the sensor values, print a 255:
Serial.print(255, BYTE);
delay(10);
}
Punctuation Method for Sending Three Bytes SeriallyIn the afternoon class, we used a punctuation method, in which one byte always had a unique value (255), and the others ranged from 0 to 254. In this method, the Arduino doesn't listen for a response from Processing, it just sends continuously. It's functionally the same as a call-and-response method, from the user's perspective, so use whichever way makes more sense to you. Here's the Arduino code:
/*
Multi-byte serial example using punctuation
Language: Arduino
This example sends a four-byte "sentence" from a microcontroller.
The first three bytes are sensor readings. The sensor readings can
range from 0 - 254. An incoming byte of value 255 is added as the
end of the sentence,
Created 3 Oct. 2007
by Tom Igoe
*/
int sensor[3]; // array to hold the sensor values
void setup() {
// initialize the serial port:
Serial.begin(9600);
}
void loop() {
// for loop to count from 0 to 2:
for (int i = 0; i < 3; i++) {
// read one of the sensors, divide by 4, put into the array:
sensor[i] = analogRead(i)/4;
// if the value is 255, truncate it so we can use 255
// as a unique value to punctuate the sentence:
if (sensor[i] == 255) {
sensor[i] = 254;
}
// print the current sensor value:
Serial.print(sensor[i], BYTE);
}
// After printing the sensor values, print a 255:
Serial.print(255, BYTE);
delay(10);
}
And here's the Processing code:
/*
Multi-byte serial example using punctuation
Language: Processing
This example listens for a four-byte "sentence" from a microcontroller.
It treats the first three bytes as sensor readings, and uses them to move
a ball on the screen. The sensor readings can range from 0 - 254.
An incoming byte of value 255 is interpreted as the end of the sentence,
Created 3 Oct. 2007
by Tom Igoe
*/
import processing.serial.*;
Serial myPort; // the instance of the Serial class
int[] sensorArray = new int[3]; // Array to hold the incoming sensor values
int arrayCounter = 0; // counter for the array elements
void setup() {
// set up the window:
size (400,300);
smooth();
// list all the serial ports:
println(Serial.list());
// pick the serial port that corresponds to your Arduino:
String portname = Serial.list()[0];
// open the port by instantiating the Serial class:
myPort = new Serial(this, portname, 9600);
}
void draw() {
// clear the window background:
background(0);
// use the Z axis of the accelerometer to set the grayscale of the ball:
fill(sensorArray[2]);
// use the X and Y axes to move the ball:
ellipse(sensorArray[0], sensorArray[1], 20, 20);
}
void serialEvent(Serial myPort) {
// read the incoming byte:
int inByte = myPort.read();
// if the byte is 255, it's the end of a set of sensor readings.
// reset the array counter to get the next set of readings:
if (inByte == 255) {
arrayCounter = 0;
}
// if the inByte is not 255, it's a sensor reading. Put it
// in the appropriate array element:
else {
sensorArray[arrayCounter] = inByte;
// increment the array counter:
arrayCounter++;
}
}
Hope that clears things up! -tigoe --- Here's a link to everyone's Journal RSS feeds. Add yours! IgoeClassJournals -tigoe ![]() ARDUINO 4 EVA |