[Book]
Main Page |Book|Search:
[Add to or Correct This Page ]

Connecting Computers and Microcontrollers

There is a good chance that you will have to cobble together a couple of computers, each speciallizing in one part of your project, and have them communicate with each other. The most common configuration is using a microctroller to sense physical event in the world and send a message to a ROC to play some multimedia in response using Director, MAX, Java or Flash. Or it might be the other way around, having mouse movements on the ROC control the positioning of a motor. The simplest way to connect between these a microcontroller and a ROC (or between other computerized devices) is using serial communication.

Protocols

A protocol is a list of agreements between the two sides of your communication. You have probably heard of many different communication protocols (eg MIDI, USB, TCP/IP).The fastest way to get going talking between most devices is using a protocol called RS232 serial protocol. We will go through and list the agreements necessary to make this kind of connection.

Physical Agreement-- The Cable

Most desktop PC's still have a RS323 port build in. It is a 9 pin female plug usually labled as COM1 or COM2 or 0|0|. USB ports are becoming more the standard on regular computers which means that you may have to get a USB to RS232 adapter especially on a mac. An RS232 port is still the most common type of port you will find for controlling stand alone devices from video mixers or medical equipment. Your microctonroller is able to speak RS232 Serial and it's close sibling TTL Serial but you will have to make a port.

USB to RS232 converter

We recommend that you solder some headers or stiff wires onto a male DB9 connector so you can plug it right into you breadboard and you can use a standard DB9 male female cable. Although there are 9 connectors in a DB9, there are only three wires that matter, transmit, recieve and ground.

Be sure to connect the transmit of one side to the recieve of the other side. When one side is the microcontroller this is easy because you get to set in software which pins to use for transmit and recieve. When connecting between two hard wired RS232 ports, you may need to insert a Null Modem adapter which crosses the rx and tx wires.

Electrical Agreement

The voltage of the electrical pulses also needs to be specified. This is where a strict interpretation of the RS232 protocol can get you in trouble when talking to a microcontroller. RS232 says that -12Volts is a yes and +12Volts is a no. Microcontroller use a system called TTL where +5 Volts is a yes and 0 Volts is a no. In practice the two sides manage to understand each other because the voltages are close enough and the logic can be "inverted" in softare. You will see in the schematic we suggest that you put in a 22k resistor on the line leading from the RS232 port to the microcontroller to protect it from the 12Volts which is bigger than it is expecting. MIDI and RS485 protocols also differ from RS232 electrically.

Timing

RS232 is an asynchronous protocol (as is MIDI RS485 and TCP/IP) which means that each side has a separate clock for counting the number of 1's and 0's coming in. The number of 1's or 0's per second is called the baud rate. The most standard baud rate for RS232 is 9600 which is about 8 bits or one letter per millisecond or but it is not uncommon to double or triple that rate. The baud rate for MIDI is fixed at around 32,500. There is another kind of serial communication called syncronous serial where one side keeps time and send pulses via yet another wire to the other side to se the rate of communication. This is common when talking between chips (eg ).

Other Agreements

There are a couple of other agreements. In RS232 you typically agree to send data in packages of 8 bits (1 byte). There are options for sending a bit at the beggining and one at the end, for send the bytes feet first or head first, to use a parity bit for error checking etc.. But these don't change much. 8 data bits, one stop bit, no parity is almost always the agreement.

Sending from a Microcontroller

‘''''''''''''BASIC STAMP TX is connected to pin 6. RX is connected to pin 7.
 inFromSerialVar var byte 
main:
	SEROUT 6, 16468, ["A"]
	SERIN 7, 16468, [inFromSerialVar]
	DEBUG ? inFromSerialVar
GOTO main 

‘''''''''''''BASIC ATOM  TX is on pin 6; RX is on pin 7
inFromSerialVar var byte 
main:
	SEROUT 6, I9600, ["A"]
	SERIN 7, NI9600, [inFromSerialVar]
	DEBUG [inFromSerialVar]
GOTO main 

‘''''''''''''PIC BASIC PRO TX is connected to pin C6. RX is connected to pin C7.
inFromSerialVar var byte 
main:
	SEROUT2 portc.6, 16468, ["A"]
	SERIN2 portc.7, 16468, [inFromSerialVar]
	SEROUT2 portc.6, 16468, DEBUG [“I got: “, inFromSerialVar, 10, 13]
GOTO main 

‘''''''''''''BX24    TX is on pin 11; RX is on pin 12
Dim InputVar(1 To 10) As Byte 
Dim OutputVar(1 To 40) As Byte 
dim outData As byte
dim inData As	byte
Sub main()
	Call openQueue(InputVar, 10)
	Call openQueue(OutputVar, 40)
	Call defineCom3(12, 11, bx1000_1000) 
	Call openCom(3, 9600, InputVar, OutputVar) 
	outData = 65
	do
		Call putQueue(OutputVar, outData, 1)
		Call getQueue(InputVar, inData, 1)
		‘ check to see if there is a byte in the input buffer;
		‘ if there is, get it with getQueue()
		If statusQueue(inputBuffer) = true then
			call= getQueue(inputBuffer, inData, 1)
			Call putQueue(outputBuffer, inData, 1)
			Debug.print cstr(inData)
		End if
	Loop
End Sub

Characters or Numbers

So far we are sending groups of 8 1's or 0's. Machines like to interpret these as a numbers using a binary coding system. Basically you give each of the 8 binary digits a weight, 1,2,4,8,16,32,64,128. You add up all the wieghts of the digits that have a one and you get the number between 0-255 equivalent of that byte. While computers like number people often prefer letters. Luckily there is a system for converting between characters and number called [ASCII]. If you are sending text it is a no brainer, you would send ASCII characters. For numbers, say the number 222, you could send one byte (a byte can hold a number up to 255) or you can send three binary bytes of the number (50) that ASCII associates with the character "2" or "222". Sending characters is slightly less efficient but much easier to send big numbers, multiple numbers (say for multiple sensors), and much easier to debug. Your microcontroller and your software on a ROC will have builtin functions for converting back and forth. The important thing is that your are consistent on both sides.
serout 6, NI9600, [DEC AVar,32,DEC BVar,32,DEC CVar, 44] 'DEC converts number to strings
or on a BX
OutputString =cstr(AVar)&chr(32)&cstr(BVar)&chr(32)&cstr(CVar)&chr(44)
Call putQueueStr(outputVar, outputString)

Terminal Software

It is highly recommended that you first try talking from your microcontroller to a terminal program before you jump to your custom software. Terminal programs are so simple they just display what is coming from the serial port on the screen and pass what you type on the keyboard on to the serial port. (It is very similar to what Telnet does with TCP/IP sockets.) It allows you to see that your microcontroller program and all the cabling and connections are are working correctly before you introduce possible errors from your custom software. The short coming is that it only interprets things as text and shows you garbarge characters for binary numbers (still comforting if they are consistant). On the PC "hyperterm" is usually built in and found under programs>accesories>communication. On a mac you can use the shareware zterm.

Serial Buffers and Serial Freeze

In order not to miss an incoming message, your microcontroller might have to lock up all other activity and concentrate on a the rx pin. You program will appear to stop until the expected number of bytes arrive on that pin. Most regular computers have what is called a buffer where bytes can be collected in in the background until your software has a chance to deal with them. This freezing up is like a "blocking function" if you are familiar with TCP/IP socket programming. Microcontroller serin fucntions usually have an escape clause called a timeout so you can manage to multitask a little bit.

 	
main:
	SERIN serin 7, NI9600, 10, noData, [inFromSerialVar]
	SEROUT serout 6, NI9600, ["A"]
	DEBUG debug [inFromSerialVarinFromMacVar]
goto main 
NoData:
	Serout 6, NI9600, [“.”]
Goto main

Sometimes the blocking can work to your advantage because it synchronizes the two computers. For instance you could have your microcontroller send some sensor readings and then freeze while waiting for a reply, thus ensuring that it is only supplying as many readings as the other side can handle. These freezing up makes it easy to institute a something that might be termed "polling" or "handshaking" or "call and response" into your protocol.

Content Formatting

Finally there will be the content of what you are sending. If you are talking to a stand along device like video mixer or a modem you will have to consult the user manual to learn the protocol or the content of the messages you send and recieve from it. If you are on both sides of the conversation, for example your microcontroller and your software on a regular old computer you will have to invent your own private conventions. As mentioned before, you will have to decide between binary number or ascii characters. You will have to decide if you want your microcontroller to be "polled" by your regular old computer. Finally if you are sending over multiple things, for instance readings from multiple sensors, you will need some method of delimiting between items within a message. If you are sending things as binary bytes you will be able to easily tell them apart just by their order, the first byte over is always for this sensor, the second for this sensor etc... If they readings are bigger than a byte or of irregular lengths, it might be easier to send things as characters instead of binary btyes and use a space character (ascii 32), comma(ascii 44) or somthing like that to delimit between the items of the message. If you or the device you are talking to does not use a "polling" method you will also need an end of transmission character to delimit one message from another. The carrage return (ascii 13) or the line feed (ascii 10) or both are often used for this purpose. The null character (ascii 0) is often used for this in TCP/IP programming. The key in picking delimiter is making sure it is never in the delimited.

General Serial Programming on a ROC

Serial Programming in Director

Although there is no serial programming interface built into Director MX, the environment is easily extensible using an architecture called Xtras. The first step in adding an Xtra to Director MX is finding and buying it. We recommend the SerialXtra from http://www.physicalbits.com, which is far and away the best one.

global serialObject, serialObjectName, serialObjectFilename
global myVar1, myVar2, myVar3
on startMovie
 	clearglobals
	-- variables for setting up the xtra.
	-- Fill in your own values from the email
	-- that you get from the licence registrar:
 
	serialObjectFilename = "SerialXtra"
	serialObjectName = "SerialXtra"
	programmerName = "your.email@someisp.com"
	serialnum = "xxx-xxxx-xxxx-xxxx "
	licenseLength = 90
 
	-- make a new instance of the xtra
	openxlib the pathname & "serialXtra.osx"
	serialObject = new (xtra serialObjectName, programmerName, serialnum, licenseLength ) 
 
	-- check that it has been created correctly 
	if objectP( serialObject ) then
		put serialObject 
	else
		alert("Instance not valid")
	end if

	-- fill in the name of your serial port below:
	serialObject.openPort("/dev/cu.USA19HS191P1.1")

	-- set the data rate, start bits, etc:
	serialObject.setProtocol(9600, "n", 8, 1)
end

on stopMovie 
	-- dispose of the xtra and close the xtra file
	serialObject.closePort()
	set serialObject to 0
	--closeXlib 
end 

on exitFrame
	doSerial
	go the frame
end 

on doSerial
	-- see if the port’s been opened:
	If serialObject.isPortOpen() then
		If serialObject.charsavailable() = 0 then
			--send a byte to ask for data
			SerialObject.writeChar(“A”)	
		End if
	
		If SerialObject.charsAvailable() >=3 then 
			--first byte sent by microcontroller:
 			MyVar = SerialObject.readNumber()	
			--next byte sent by microcontroller:
 			MyVar2 = SerialObject.readChar()
			--third one sent by microcontroller:
			MyVar3 = SerialObject.readChar()	
		End if
	End if
end 

Serial Programming in Java

The classes that you will need to perform serial communication are not included with your standard installation of Java. Your first step is to find the classes that will work with your hardware platform. For Windows, this is easily done by visiting the Suns java site: http://java.sun.com/products/javacomm/index.html. For the Mac and other platforms you can buy classes from http://www.serialio.com/. For free versions for the Mac OS 9, try http://homepage.mac.com/pcbeard/javax.comm.MRJ/. For Mac OS X or Linux, try http://www.rxtx.com; For other platforms, try http://republika.pl/mho/java/comm/. Theoretically, all of these will conform to Sun’s communications API, so your code can be pretty close to the same. The installation is the hardest part, so you should actually read the readme file that comes with whatever package you use. On a PC you need to place 3 files, “comm.jar” in your <JDK>/jre/lib/ext/, “javax.comm.properties” in <JDK>/jre/lib/, and “win32com.dll” in <JDK>/jre/bin/. Using RXTX on OSX you need to put "libSerial.jnilib" and "RXTXcomm.jar" into /Library/Java/Extensions/.

import javax.comm.*;
//import gnu.io.*; //use this instead of javax.com if you are using RXTX
import java.io.*;
import java.awt.*;
import java.util.*;

public class SerialExample extends Frame implements SerialPortEventListener {
	static SerialExample myFrame;
	//we are making this into a frame so we can track the mouse
	SerialPort mySerialPort =null;
	InputStream in;
	OutputStream out;
	byte x = 50;

	static public void main(String[] args) {
		// Print out the list of serial ports, 
		//in case you don't know the name"
		Enumeration portList = CommPortIdentifier.getPortIdentifiers();
		while (portList.hasMoreElements()) {
			CommPortIdentifier portId = (CommPortIdentifier)portList.nextElement();
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL){
				System.out.println(portId.getName() + " " +portId.getCurrentOwner());
			}	
		}


		// Change the port name below as needed on the Mac:
		myFrame= new SerialExample("COM1",9600);

		//the following is all just window management
		myFrame.setVisible(true);
		myFrame.setLocation(new java.awt.Point(0, 0));
		myFrame.setSize(new java.awt.Dimension(255, 450));
		myFrame.setLayout(null);
		myFrame.setTitle("Serial");
		//add a listener for closing the window, in that event call the windowClosing method
		myFrame.addWindowListener(new java.awt.event.WindowAdapter() {public void windowClosing(java.awt.event.WindowEvent e) {myFrame.thisWindowClosing(e);}});
		//add a listener for moving the mouse in the window,in that event call the mouseMoved method
		myFrame.addMouseMotionListener(new java.awt.event.MouseMotionAdapter(){public void mouseMoved(java.awt.event.MouseEvent e) {myFrame.mouseMoved(e);}});
	}

	public SerialExample (String whichPort, int whichSpeed) {
		//which port you want to use and the baud come in as parameters

		try {
			//find the port
			CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(whichPort);
			//open the port
			mySerialPort = (SerialPort)portId.open("SerialExample" + whichPort, 2000);
			//configure the port
			try {
					mySerialPort.setSerialPortParams(whichSpeed,
					mySerialPort.DATABITS_8,
					mySerialPort.STOPBITS_1,
					mySerialPort.PARITY_NONE);
			} catch (UnsupportedCommOperationException e){System.out.println("Probably an unsupported Speed");}
			//establish streams for reading and writing to the port
			try {
				in = mySerialPort.getInputStream();
				out = mySerialPort.getOutputStream();
			} catch (IOException e) { System.out.println("couldn't get streams");}
			try {
				mySerialPort.addEventListener(this);
				mySerialPort.notifyOnDataAvailable(true);
			} catch (TooManyListenersException e) {System.out.println("couldn't add listener");}
			try {
				//send an initial character in case your microcontroller is waiting:
				out.write("A".getBytes());
		 	} catch (IOException e) {System.out.println("couldn't send byte");}
		}
		catch (Exception e) { System.out.println("Port in Use");}

	}

	public void serialEvent(SerialPortEvent event) {
		if (event.getEventType()== SerialPortEvent.DATA_AVAILABLE) {
			try {
				if (in.available() >= 3) {
				 // we will wait for three sensor readings
					int heat = in.read();
					int light = in.read();
					int pressure = in.read();
					//do something with these numbers
					System.out.println(heat + " " + light + " " + pressure);
					out.write(x); //send the mouse position back
				} //end if for data available
			 } catch (IOException e) {}
		} //it’s a serial port event
	}

	void thisWindowClosing(java.awt.event.WindowEvent e) {
		myFrame.setVisible(false); // Close the window when the close box is clicked
		myFrame.dispose();
		System.exit(0);
	}
	public boolean mouseMoved(java.awt.event.MouseEvent evt){
		x = (byte) evt.getX();
		// Put the mouse coord into a variable called x
		return(true);
	}
}

Serial Programming in Processing

int bgcolor;			// background color
int fgcolor;			// fill color
String serialString = "";	// where we'll put what we receive serially
int serialCount = 0;	// a count of how many bytes we've received
float xpos, ypos;		// Starting position of the ball

void setup() {
	beginSerial(); 	// Default start serial at 9600 baud
	size(200, 200); 	// 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;
	serialWrite(65); // send a capital A to start the MC sending
}

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

void serialEvent() {
	processString((char)serial);
}

void processString(char inByte) {
	// add the latest byte from the serial port to the string to be parsed:
	serialString += inByte;
	
	// update the string length:
	serialCount = serialString.length();

	// if we have 4 bytes, parse the string:
	if (serialCount > 2 ) {
		fgcolor = (int)serialString.charAt(0);
		xpos = (float)serialString.charAt(1);
		ypos = (float)serialString.charAt(2);

		// clear the string when we're done, and ask for more:
		serialString = "";
// send a capital A to request new sensor readings:
		serialWrite(65); 	
	}
}

Serial Programming in Max

Serial Programming in Flash

[Serial Server]relays bytes back and forth from an internet socket connection to a hardware serial port. This is especially useful for software like Flash which has an easy time making socket connections and a hard time making serial connections. This will allow you to connect to a device with an RS232 port (eg, modem,videomixer,compass...) or to connect with sensors and actuators on a microcontroller (eg Basic Stamp, PIC, BX, Atom,AVR...). Maybe serial extensability will built into flash soon in which case you will not need this. I suppose it could also be useful for controlling the serial port of one machine from another machine but I have never needed to do that.

Synchronous Communication

Serial communication can be broken up into two broad categories: synchronous and asynchronous. RS232 is very useful but many small modules or IC chips use a differeent kind of serial communication called synchronous serial communication. This uses two wires, one for the data and one called the clock that controls the rate at which the data is sent. One device acts as the master and sends a timing pulse on the clock wire every time it is ready to send or receive a bit of data. The term shifting is used for synchronous serial communication, because with each clock pulse you shift over the next bit of data. Most microcontrollers all have commands called shiftin and shiftout for sending and receiving synchronous serial communication. There are many styles of synchronous serial communication. Looking at the data sheets for various devices, you’ll see I2C, SPI, and Microwire, among others. Though there are some differences between the styles, they all shift bits between devices on the clock pulse.

Often, there are connections for both sending and receiving, just as with asynchronous serial communication, for a total of four connections. One side of the communication is called the master because it supplies the timing pulses on the clock connection. The connections for synchronous serial are usually labeled MISO, for Master In, Slave Out (meaning that the data is going from the slave to the master) and MOSI, for Master Out, Slave In (going from the master to the slave). Sometimes you’ll see the terms SDI (serial data in) and SDO (serial data out). The clock will sometimes be labeled SCK, SCLK, or CLK.

In addition to the data lines, there’s usually a chip select connection. Several synchronous serial devices can be connected to one bus, meaning that you can run the data lines in parallel from one master controller to several slaves. In order to direct the flow of data in synchronous serial, each slave gets its own chip select connection to the master. This way, the master can set a given slave’s chip select pin to tell it to listen and to tell all the other chips to ignore the data. Generally, the chip select is taken low (given 0 volts) to select a given chip and taken high (given 5 volts) to tell the chip to ignore data. This is called an active low pin, and it’s indicated by a bar over the top of the pin in the schematic.

Checkout the the shiftin and shiftout commands for your microcontroller. You will have to supply which pins you are using as data, and clock, whether you are sending info feet first or head first (probably MSBFIRST) and finally a variable to be sent or to be filled with incoming data.

USB

It is possible to build a USB port on your microcontroller. In particular their is some nice software circulating for doing this on a PIC. I would personally skip this step by using a USB to RS232 serial convert until more interesting technologies like bluetooth and ethernet adapters come down in price. For higher level prototyping I would try to leap frog past all these Bluetooth, IR, RF solution and get going with the wireless internet stuff.

Ethernet

I hope this is where things are going. I would be okay about saying my final good bye's to my beloved rs232 port if it was replaced with a cheap ethernet port. There are some low level solutions out there where you write all the software to communicate using the IP protocol on to your microcontroller. For now a better, higher level solution is a [RS232 to Ethernet convert] or better yet an [RS232 to Wireless Ethernet converter.]

[Add to or Correct This Page]|[Yes, this is a Wiki]