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, 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% gcc -o arduino-serial arduino-serial.c
laptop% ./arduino-serial
Usage: arduino-serial -p <serialport> [OPTIONS]

Options:
-h, --help Print this help message
-p, --port=serialport Serial port Arduino is on
-b, --baud=baudrate Baudrate (bps) of Arduino
-s, --send=data Send data to Arduino
-r, --receive Receive data from Arduino & print it out
-n --num=num Send a number as a single byte
-d --delay=millis Delay for specified milliseconds

Note: Order is important. Set '-b' before doing '-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 descriptor
  • int serialport_read_until(int fd, char* buf, char until)
    – read from serial port into a buffer until a given character is received

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.

47 Responses to “Arduino-serial: C code to talk to Arduino”

Obviously you could also use “screen” to communicate with the Arduino (or any serial device) using the following command:

screen /dev/cu.usbserial 9600

screen is bidirectional, so you can send and receive data.

Yup, totally.

I’ve only ever used screen in interactive sessions. I’m not sure how one would go about routing screen to a proram or sending binary (non-ASCII) data that is present in many Arduino designs.

I haven’t tried it, but there’s probably some way to have the “expect” command interact with screen as a simple way to get data back and forth from the Arduino in a semi-automated way. However, this is going down the territory of “many ways to solve the same problem” territory Tod mentioned.

If you do want to do this using a dynamic language, the ruby/serialport library makes it really easy in Ruby. I just put up some video and instructions for a hello world.

Todbot — Thanks for all your great posts on Arduino (especially the Spooky Arduino series), I’m in the process of learning this stuff with a little study group of other absolute beginners and they’re been totally indespensible. Keep up the great work!

Thanks, I’m glad people are finding the Spooky Arduino stuff useful. It was a blast to work on.

And, wow, Ruby can do serial ports now? That’s awesome. Okay I gotta try this out….[follows your link, watches the rad movie, looks a bit more, then 2 minutes later] Yup, works like a charm. I did:

% wget http://rubyforge.org/frs/download.php/72/ruby-serialport-0.6.tar.gz
% tar xvzf ruby-serialport-0.6.tar.gz
% cd ruby-serialport-0.6
% ruby extconf.rb
% make
% sudo make install
% emacs light.rb
% ruby light.rb

With Ruby and its friendliness towards Ajax websites and the ability to do serial ports, I can imagine some really interesting “Web2.0″-type websites that interact with the real world via Arduino.

Very useful code, thanks!

However, I’ve found that -under FC6-, sometimes the seriaport_read_until returns a error 11 (resource temporarilly unavailable) in the read() call. I think it is not a problem with the software -obviously- since a “cat

I’m trying to get the hello world program to work I’ve downloaded the modifed Justin Mcbride file (I’m using linux) compiled and ran
./arduino-serial -b 9600 -p /dev/ttyUSB0 -r

the output is then read
read:

My port is on ttyUSB0 any clues?

After some experimentation it does return hello world I just need to catch it at the right time.

Hi Todbot,

Great site, I’m loving all the Arduino content. I’m new to Arduino and I’m trying to understand a few things. In the ruby example at ComputerKraft, they have 2 files - the sketch that’s written in Processing and the light.rb file. Do you need to write a sketch in Processing when you want to use ruby? Is it possible to write a ruby script that does what the Processing sketch does? I would like to be able to just write the code once in Ruby. And last, but not least, can you do an Arduino - Ruby example as you did with C?

Thanks for all the great content!

Jose

Hi Jose,
I’m not familiar with the Ruby example at ComputerKraft so I can’t speak to it. However, you don’t need Processing for Arduino or Ruby. Processing is just one way of writing programs (in this case, Java programs) that can talk to serial ports and thus Arduino. Because Processing is so easy to use and it shares the same style GUI as the Arduino programmer, it is a common tool for showing how you can interface Arduino with a computer.

Perhaps what the ComputerKraft example is doing is creating a Processing sketch that receives network requests then forwards them on to Arduino. The Ruby program then just connects to a network socket and doesn’t need to have serial port drivers.

In the example at ComputerKraft there’s an Arduino sketch, not Processing - sorry… that receives serial requests. In essence, it is nothing more than a case function that when selected turns on the corresponding LED. The Ruby program basically takes input from the user, parses it and forwards it over to the Arduino sketch via serial.

What I’m trying to understand is this: In order to use Ruby or any other language to speak to Arduino via serial, do I need to have an Arduino sketch already running in Arduino expecting serial requests?

minicom is another great way to read/write to the arduino. I have the USB model and just set my minicom serial port to /dev/ttyUSB0. Works great in Fedora Core 6.

[…] Here is arduino-serial.c, 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.” - Link. […]

Hi everybody,

I am introducing in this new world called Arduino, here is my problem:

I have my arduino working and I can receive data from it using:

tail -f /dev/ttyUSB0 >> “file.txt”

After trying with the arduino_serial.c, I was not sucesfull, I guess I have the same problem that Peter had.

Using “tail” would be enough for me since I only want to receive data from it. But when I say to arduino to work at baudrates higher than 9600. “tail” is not giving the right data (Strange symbols).

My question is do you know how to set the baudrate in order to use “tail” with higher baudrates?

Anyidea will be wellcome!

Hi Javi,

To change the baudrate of serial ports, you use the “stty” command before your tail.

If you see the “roomba-tilt.pl” program on the Roomba Tilt project, you’ll see a complete invocation of stty that allows full bidirectional binary transmission.

But if all you need to do is change the speed, then:

% stty -F /dev/ttyUSB0 57600

is all you need to change the baudrate to 57600 bps.

hi there,
i’m sorry if you cover this elsewhere, but i am just getting started in trying to program in C for the avr… do you have any recommendations on resources? just looking start with a simple blinkie code so i can figure it all out. i would really appreciate it. thank you!

Hi Leah,
One of the easiest ways to get into C AVR programming is the Arduino site itself: the Tutorials, Reference, Hacking, and Playground sections are chock full of good intro material.

If you’re interested in plain vanilla AVR programming without the thin veneer of Arduino, one of the best books out there to get started is the “C Programming for Microcontrollers” available from SmileyMicros.com. It’s based around the Atmel AVR Butterly board, a tiny $20 demo board that’s a lot of fun to play with.

Once you get a bit familiar with AVR C, you’ll want to bookmark the AVR Libc page. Libc is the collection of C libraries that is the “standard” set of libraries containing all the functions you’re used to in C. In the case of AVR Libc, it’s also the libraries that help you interact with the on-chip hardware.

I can’t get open() to work, it keeps telling me the file does not exist. I can open the serial stream just fine with ’screen’ from the terminal, but this damn open() just returns an error. Any ideas?

That’s really odd. What’s the exact invocation you’re using and the exact error messages you’re seeing? If this is Linux, I’d say it’s a permission problem with the serial port device file and screen gets around it by being setuid root.

its Mac OsX Tiger, under the terminal.

I managed to access properly from my c code by using sudo

sudo ln -s /dev/tty.usbserial-* /dev/tty.arduino

although I havent read exactly what that does but im using the alias to access it and it works.

my original serial path was /dev/tty.usbserial-A10?16fZ

I’m guessing my c code just hated that ? mark.

That’s very strange. I’ve never seen a USB-to-serial driver create a virtual serial port that wasn’t just alphanumeric. Creating a symlink to a more reasonable name like you did is probably the best solution.

Aside: A symlink (”symbolic link”) is the unix way of doing aliases. The “ln -s” command creates symlinks. The “sudo” command lets you “do” things that normally a “su”per user (admin user) can only do. Creating symlink in the /dev directory is one of those things.

Again, it’s very strange to have a question-mark in the serial port name. Are you running the latest serial drivers that come with Arduino? Has anyone on the Arduino forums had a similar problem?

how would I got about upgrading the serial drivers?

Download the latest version of the Arduino software. Inside there is a directory called “drivers” containing driver installers.

ah, this is a new installation already… so maybe a way to change my arduino’s serial number?

I think /dev/tty.usbserial-A10?16fZ works from the command line beacuse bash interprets ? as a wildcard (whereas C doesn’t), so the ? is a typo (kinda like how /dev/tty.usbserial-A10*16fZ works)

Hi Tod great site. I’m new with arduino and C.
I need that the programm send binary not ascii e..g -s 65 = a and not 65. How can I change the arduino-serial.c ?
Thanks sorry for my english I hop you understand my Question
Klaus Germany Berlin

Hi Klaus,
To send the byte value 65 instead of the character ‘a’ (ascii 65), you need to do an ascii-to-integer conversion. There’s a function called “atoi()” in C that does this. There’s a more general function called “strtol()” (”string to long”) that will even parse decimal, hex, and other number formats.

I’ve updated the arduino-serial.c program above to do this with a new option ‘-n ‘.

To use it you would do something like this:

% arduino-serial -b 19200 -p /dev/USBS0 -d 2000 -n 65 -r

This will open up serial port “/dev/USBS0″ at 19200 bps, wait for 2 seconds, then send the number 65 and read back any response terminated by a newline.

Hi Tod, that’s great - I’m so thankfull! I use it to write on an LCd Screen (4 lines 40 Col) and so I can send the bytes to control it.
best wishes and an hapy new year
Klaus

[…] was looking at this link on the todbot blog. It is a utility C program that sends some serial data to your Arduino. I […]

I am trying to write a c program that logs the data from the serial port then saves it to a file.

I have been having some trouble reading the data from the port. The port seems to be set up correctly( I get a 3 back) but when I try a read I get a -1.

Arduino monitor and cutecom can read the arduino just fine.

thanks

Ok I got some output by removing the O_NDELAY from the open.
The problem now is the data seems to be garbage.

Any thoughts?

Thanks

I don’t think removing O_NDELAY on serial port open() will affect your issues. But it will probably make it so some of your reads() never time out (I’ve not checked this with serial ports)

Does the arduino-serial.c program read data correctly for you? (it will print to the stdout, but it’s easy to change that to print to a file)

The fact that you’re reading garbage means either you’re at the wrong baudrate, wrong number of stopbits, or you’re not checking the return value from read() to see how many bytes were actually read.

Arduino features an FTDI chip to do serial communication with an USB host, but of course this limits us to use the FTDI driver, and thus forces us to install drivers and limits us to our own software. Since the USB spec does not allow bulk endpoints for low speed devices, it’s always possible that a new version of e.g. Windows does not allow them.

Here’s a Python version of arduino-serial.c:
http://lemonodor.com/archives/2008/02/arduino_serial.html

I have succeeded in my project to use Diecimila
with SimpleMessageSystem & linux, via shell scripts.
Run this now: ‘wget http://207.14.167.161/SMS1.tgz
It only works when my system is booted, so keep trying. Finally got the right data format from readAD-1: Comma-separated values. This imports to OpenOffice calc easily, for further analysis or graphing. Try it.

A little off topic, as this is more of a c question.

I am Very new to all of this, so please pardon what is probably a stupid question;

In your C code, you are parsing out the options sent to the app with a while statement.

Why do you have a ‘while(1) { }’ Isn’t that true by default?

and, how is this able to parse all options?

any illumination on this is greatly appreciated….

Thanks!

Christopher Lund

Hi Christopher,
Your questions aren’t stupid. In fact they get some of the less clear aspects of how people typically write C code.

The while(1){ } block is used to wrap the call to getopt_long(). Each time that function is called, it parses another chunk of the command line argument string. So the while(1){ } says “keep parsing forever”. But there is a if (opt==-1) break; that will break out of that while loop if there are no more arguments to parse.

Structuring the code this way is a way you’ll see some simple C programs written where it implies that program’s functionality is simple and controlled entirely via command-line arguments. That is, the style of the source code implies the intended use of the program. You’ll find this kind of philosophy in a lot of C code. There’s so many ways to do the same thing in C that people adopt “idioms” in how they code to hint at what they’re trying to do. I just copied it from some other code I had. :)

Another common idiom for loops which are either “infinite” or broken out of in the middle is “for(;;) { … }”. This has the advantage of having the control conditions be explicitly empty - you don’t have to look twice to check if the “1″ is a lower case letter L, for example.

This works great in Fedora Core 6.

How would implement this in Visual Studio .NET 2005 ?
The POSIX libraries are not supported.

Hi Jason, Sorry, no clue, I don’t use Windows; I thought that it had the POSIX libraries. I seem to recall seeing a Visual Basic serial port library a while back, perhaps generally usable in .NET. Try googling around for “VB serial library” or similar.

hi there
will all this things work with geexbox too?
can i implement a package to the geexbox iso to get it working?

Hey Todd. Im basically trying to read my arduino from my /dev/ttyUSB0 (which works fine with screen). I found out that it exits in the serialport_read_until() with -1 (can’t read). I find this a bit strange since my arduino is just spamming the serial, so there should be something. Any ideas? (btw the baudrate is right so its not that.)

Hi harohase,
I’m not familiar with geexbox, but it looks like Linux, so I don’t see why you couldn’t make an arduino-serial package for it.

Hi Casper,
I must admit the serialport_read_until() function is the least polished part of arduino-serial. So there might be a logic problem.

However, if you’re using an Arduino Diecimila or similar newer Arduino, you may be trying to read while the board is in reset, since on Mac OS X & Linux, opening the serial port resets the Arduino.

To deal with this, insert at least a 2-second delay before reading. Here’s an example that inserts a 5-second delay between opening the open and reading:

% ./arduino-serial -b 9600 -p /dev/ttyUSB0 -d 5000 -r

Hi everybody !

I have a strange problem.
The program is working when I have just upload the program to the arduino (with the arduino software), it’s working working very well.

But If I reboot, I try to configure the TTYUSO with this :
stty -F /dev/ttyUSB0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts

I try to launch the program : not working :/

I launch screen : screen /dev/ttyUSB0 9600

I stop screen, launch the program : it’s working.

What’s wrong with my configuration ??

Hi Batoub,
What is the exact arduino-serial command you’re using? Are you trying to read data? If so, be sure to have at least a 2-second delay (see my previous comment) to deal with the Arduino’s reset.

It may be that screen is opening the serial port but not closing it, so by the time arduino-serial is used, it’s past the reset delay.

Something to say?