[NOTE! arduino-serial has been greatly updated. See the “Arduino-serial: updated!” post for details]
The Arduino’s USB port is actually a serial port in disguise. To your computer it appears as a ‘virtual’ serial port. This is good news if you want to write custom code on your computer to talk with the Arduino, as talking to serial ports is a well-solved problem. (Unfortunately, so well-solved that there’s many ways of solving it.)
On the Arduino forum there’s been a few requests for some example C code of how to talk to Arduino. The nice thing about standard POSIX C code is that it works on every computer (Mac/Linux/PC) and doesn’t require any extra libraries (like what Java and Python need). The bad thing about C is that it can be pretty incomprehensible.
Here is arduino-serial.c (github for full source), a command-line C program that shows how to send data to and receive data from an Arduino board. It attempts to be as simple as possible while being complete enough in the port configuration to let you send and receive arbitrary binary data, not just ASCII. It’s not a great example of C coding, but from it you should be able to glean enough tricks to write your own stuff.
Usage
laptop% ./arduino-serial Usage: arduino-serial -b <bps> -p <serialport> [OPTIONS] Options: -h, --help Print this help message -b, --baud=baudrate Baudrate (bps) of Arduino (default 9600) -p, --port=serialport Serial port Arduino is connected to -s, --send=string Send string to Arduino -S, --sendline=string Send string with newline to Arduino -r, --receive Receive string from Arduino & print it out -n --num=num Send a number as a single byte -F --flush Flush serial port buffers for fresh reading -d --delay=millis Delay for specified milliseconds -e --eolchar=char Specify EOL char for reads (default '\n') -t --timeout=millis Timeout for reads in millisecs (default 5000) -q --quiet Don't print out as much info Note: Order is important. Set '-b' baudrate before opening port'-p'. Used to make series of actions: '-d 2000 -s hello -d 100 -r' means 'wait 2secs, send 'hello', wait 100msec, get reply'
Example Use
Send the single ASCII character “6” to Arduino
laptop% ./arduino-serial -b 9600 -p /dev/tty.usbserial -s 6
This would cause the Arduino to blink 6 times if you’re using the serial_read_blink.pde sketch from Spooky Arduino.
Send the string “furby” to Arduino
laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -s furby
Receive data from Arduino
laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -r read: 15 Hello world!
The output is what you would expect if you were running the serial_hello_world.pde sketch from Spooky Arduino.
Send ASCII string “get” to Arduino and receive result
laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -s get -r read: d=0
Internals
There are three interesting functions that show how to implement talking to serial ports in C:
int serialport_init(const char* serialport, int baud)
— given a serial port name and a speed, return a file descriptor to the open serial port.int serialport_write(int fd, const char* str)
— write out a string on the given a serial port file descriptorint serialport_read_until(int fd, char* buf, char until, int timeout)
— read from serial port into a buffer until a given character is received or timeout reached
You can and should write improved versions of the read and write functions that better match your application.
Update 8 Dec 2006:
Justin McBride sent in a patch because it turns out Linux’s termios.h doesn’t define B14400 & B28800. I’ve updated arduino-serial.c to include the patch, but commented out for now. No one uses those baudrates much anyway. :) If you need them, uncomment the additions out, or better yet, download Justin’s tarball that includes the changes and a Makefile to auto-detect your platform.
Update 26 Dec 2007:
Added ability to sent binary bytes with the ‘-n’ flag.
Added a delay option so you can open a port, wait a bit, then send data. This is useful when using an Arduino Diecimila which resets on serial port open.
Update 29 Apr 2013:
I apologize to everyone who has commented on this post but who hasn’t received a reply. This code has had a much longer life than I expected and it was hard to get back to it to fix some of its obvious deficiencies.
I did finally get back to it (but not the comments). I’ve rewritten arduino-serial a bit and added some new options. Hopefully this will address many of the issues people have had. You can read about the changes in the “Arduino-serial: updated!” post.
Also, arduino-serial now lives on Github at:
https://github.com/todbot/arduino-serial
Please post issues and patches there. Thanks!
I just downloaded the C code along with the two example sketches. When I try the read example, I get a jumble of funny looking characters back. I tried inserting a delay I get the message:
./arduino-serial: invalid option — ‘d’
and when I look at the source code, there doesn’t appear to be a delay option in there. Any suggestions?
I am sending data to the arduino with your script but it only works sometimes other times it does’nt. I have the resister from the reset pin to the 5volt pin so reset is disabled. I have tried both delays before and after sending the command but it stills works sometimes and others it doesn’t. I also tried removing the resistor and also used the delays and still no go. Any ideas?
Thanks,
Hi piercelayne,
Try using the “-d” option to insert a delay before you send characters. That is, try doing:
When you open the serial port, the Arduino reboots, so you have to wait for the reboot process to complete before you can send it data.
So, I am a total nice when it comes to this. I am using a mac and am trying to figure out what I am to do with the arduino-serial.c file. I keep typing “laptop% ./arduino-serial -b 9600 -p /dev/tty.usbserial-A900adrY -s 6” into Terminal with serial_read_blink.pde loaded to my arduino to no avail. I have spent the better part of the day trying to figure it out. So, if someone could please point me in the right direction I would greatly appreciate it.
Hola estoy usadon el archivo arduino_serial.py, y escribo la siguiente linea para ejecutar:
python arduino_serial.py -b 9600 -p /dev/ttyUSB0 -r
pero me da el siguiente error.:
—-
Traceback (most recent call last):
File “arduino_serial.py”, line 173, in
main(sys.argv)
File “arduino_serial.py”, line 146, in main
print “Read %s” % (port.read_until(‘\n’),)
File “arduino_serial.py”, line 107, in read_until
n = os.read(self.fd, 1)
OSError: [Errno 11] Resource temporarily unavailable
—-
espero me puedan ayudar. porque no se como escribir un programa para arduino en python o que arduino pueda entender python.
hi,
@jack (February 11):
I had problems with the auto-reset on the Arduino Duemilanove as well. And I don’t really want to do any hardware modifications.
I added the following to the source (around line 225):
// turn off HUPCL to avoid reset
toptions.c_cflag &= ~HUPCL;
This isn’t perfect. The first call to arduino-serial still resets the device and whatever had been send is lost.
Any calls to arduino-serial after that work perfectly. It seems the setting is remembered until the next reboot.
Even something like:
echo “H” > /dev/ttyUSB0
work after the first call to arduino-serial (no reset).
hi~
i really new in pic and C programming..
but i need to study of how detecting the sensor and counting it..
canu give some basic code for sensor that i can study first before i build a new code..
The python one seems to be working (to some degree haha). Thank you for your time.
Hi Nathan,
I suspect Windows’ approach to serial ports is fundamentally different than that of unix-like OSes. So I’m unsure you’d be able to get arduino-serial to work without a substantial rewrite.
You might have much better luck getting arduino_serial.py, a Python implementation of arduino-serial. The nice thing about arduino_serial.py is that it uses the pyserial Python library, which does work on Windows.
Hi,
I know this isn’t really the place to ask this, but I have looked everywhere and tried for days, to no avail. My task is to have the arduino(s) taking readings of it’s environment (temp, light, humidity etc), which is sent back to a computer via USB/ethernet. The computer has a program which decides the appropriate reponse and tells the arduino to switch on the hot water, take the washing in etc.
When I attempted to compile your program (using code blocks, MinGW), I found termios.h, ioctl.h, and getopt.h were missing. I tried to include these, but was only returned more errors. I am sorry, I don’t know much about programming, but you seemed to cheerfully answer querys, so, yeah… Once I have a program that communicates, I am sure I will be fine.
Hi Sergio,
Turns out every Arduino sketch you write is actually C code too! If you want, you can write more complex C functions within your Arduino sketch and use them with no trouble. This is one of the nice things about the Arduino environment.
How can i progem my arduino using a c lenguage environment, it would be great because of being more experienced in c. apreciate feedback.
FTDI & teensy++ are both much faster than the arduino usb interfaces the teensy site shows in its usb serial exaple a high speed serial interface that the virtual com port goes as fast as it can in the benchmark example. Has anyone documented virtual serial port speed?
high duty of CPU is due to the reason that this program never close serial previously opened
any way to set DTR to off (in order to avoid arduino autoreset?
Hi Tyler,
Try putting the delay before the send. You need to wait for the Arduino to start up before sending it data. Like this:
arduino-serial -b 9600 -p /dev/ttyUSB0 -d 5000 -s ra -r
I increased the delay in case you have an older Arduino.
If that doesn’t work, then I’d need to know what the sketch is like you’re running on the Arduino before being able to help more. For instance, depending on how your sketch is set up, you might need to add a delay between sending and receiving because your PC is often faster with serial than the Arduino:
arduino-serial -b 9600 -p /dev/ttyUSB0 -d 5000 -s ra -d 200 -r
That inserts a 200msec delay between sending and receiving.
Hi todbot,
I’m using your code and everything seems to work fine except when reading back a response. It seems to only echo back the input as a response.
I type-
$arduino-serial -b 9600 -p /dev/ttyUSB0 -s ra -d 2000 -r
where ra should read back a pin value and does through serial monitor and cutecom. I’ve tried the delay in various places and no delay at all. Any idea why it would only echo back the input?