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. Hi Carl,

    Your command looks good. But since “arduino-serial” was written back before the auto-resetting Arduinos, you may want to add a slight delay before sending the “a” to let the Arduino come out of reset. That is, try:

    ./arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -d 2000 -s a

    This will cause arduino-serial to open the serial port (which causes the Arduino to reset), wait 2 seconds, then send an “a”.

  2. Thanks, been trying a bunch of variations of the command above that sends a single character
    but no go yet. I substituted the name shown in the Arduino app for the board and tried this to send it an
    “a” but still no joy.

    ./arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -s a

    Any thing else I might try.
    Very much appreciate your help.

    Carl

  3. Thanks, been trying a bunch of variations of the command above that sends a single character
    but no go yet. I substituted the name shown in the Arduino app for the board and tried this to send it an
    “a” but still no joy.

    ./arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -s a

    Any thing else I might try.
    Very much appreciate your help!

    Carl

  4. Hi Carl,
    Yup, those commands are run from Terminal.app. When you open Terminal up, you will see your computer name instead of “laptop”.

  5. Dumb question I’m sure, but are these commands executed from the Terminal app?
    Also how do I define my machine as opposed to the “Laptop” used in the samples?

    Thanks,

    Carl

  6. To those getting gibberish when reading,
    Are you placing the -d before the -r ?

    example working command:

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

  7. Well, it seems there really isn’t a solution here. Too bad for the lack of support (or suggestions), I really liked this library.

  8. By the way, even using CoffeeNinja’s example I get the same gibberish (namely: testtest, tt, tetest), even after adding a delay…

  9. Thanks for the fast reply and for any insight. Yes, I am using serial.println(). As I mentioned, I can read the serial well using other methods, including a very simple python script I wrote.

    Here’s the very simple sketch:

    
    int ledPin = 13;   // select the pin for the LED
    int i=0;           // simple counter to show we're doing something
    
    void setup() {
      pinMode(ledPin,OUTPUT);   // declare the LED's pin as output
      Serial.begin(9600);        // connect to the serial port
    }
    
    void loop () {
      Serial.print(i++);
      Serial.println(" Hello world!");  // print out a hello
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
    }
  10. Hi,

    Thanks for this great library. I am having issues with it, when trying to read from serial. I am using, as a test case, the Hello World program which is supposed to output: “0 Hello world!” “1 Hello world”. Instead I have only random chunks, such as: “0 world!”, “0Hello world!”, “0 H world”, etc…

    I tried several delay times, with similar results. I wonder, why isn’t the system reading the full string?

    Thanks for any insight.

  11. I am getting jibberish when reading with this, any ideas?

    ./arduino-serial -b 9600 -p /dev/ttyUSB0 -r
    read: ?/|?5|?

    The jibberish changes even though I’m writing a static string of “test” to the serial port from arduino.

    Baud rates are the same, serial monitor from arduino IDE and cat /dev/ttyUSB0 shows “Test” which is what I would expect.

    Sketch:

    void setup(){
    Serial.begin(9600);
    }

    void loop(){
    Serial.println("test ");
    delay(1000);
    }

Leave a Reply

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