Arduino-serial: C code to talk to Arduino

[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 descriptor
  • int 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!

186 Replies to “Arduino-serial: C code to talk to Arduino”

  1. 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.

  2. 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.

  3. 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?

  4. 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.

  5. 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!

  6. 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.

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

  8. Pingback: Daily Clerks
  9. 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.

  10. 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?

  11. 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.

  12. 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

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

  14. 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?

  15. 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

  16. 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.

  17. 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!

  18. 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.

  19. 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.

  20. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *