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~
    I am trying to cross compile Arduino-serial.c with gcc-mips , I got

    file /usr/bin/arduino-serial
    /usr/bin/arduino-serial: ELF 32-bit MSB executable, MIPS, MIPS32 version 1, dynamically linked (uses shared libs), with unknown capability 0x41000000 = 0xf676e75, not stripped

    but it gives

    root@OpenWrt:/dev# arduino-serial -b 9600 -p /dev/ttyUSB0 -r
    read: p

    all the time instead of

    root@OpenWrt:/dev# cat < /dev/ttyUSB0

    723 Hello world!

    724 Hello world!

    725 Hello world!

    726 Hello world!

    any solutions?

  2. Hi
    I’ve alredy solved it it was the autoreset funktion!!
    Thanks for this helpful site and your great code

    Lukas

  3. Hi I`m using the same comand as everybody else but it doent work.
    the arduino DOES recive data but doesnt react as it should.
    the funny thing: It works when i leave the arduino serial console open
    But why and how to solve this???

  4. It seems like this is somewhat of a common issue and it is my Uno resetting itself each time the serial port is open.

    Below is ome text I found describing the issue, this is based on the Duemilanove but I’m guessing it’s the same for the Uno.

    I read that if you disable DTR on the serial port, then that also solves the issue, is this something that arduino-serial will do?

    Thanks again.

    Phil

    Automatic (Software) Reset

    Rather then requiring a physical press of the reset button before an upload, the Arduino Duemilanove is designed in a way that allows it to be reset by software running on a connected computer. One of the hardware flow control lines (DTR) of the FT232RL is connected to the reset line of the ATmega168 or ATmega328 via a 100 nanofarad capacitor. When this line is asserted (taken low), the reset line drops long enough to reset the chip. The Arduino software uses this capability to allow you to upload code by simply pressing the upload button in the Arduino environment. This means that the bootloader can have a shorter timeout, as the lowering of DTR can be well-coordinated with the start of the upload.

    This setup has other implications. When the Duemilanove is connected to either a computer running Mac OS X or Linux, it resets each time a connection is made to it from software (via USB). For the following half-second or so, the bootloader is running on the Duemilanove. While it is programmed to ignore malformed data (i.e. anything besides an upload of new code), it will intercept the first few bytes of data sent to the board after a connection is opened. If a sketch running on the board receives one-time configuration or other data when it first starts, make sure that the software with which it communicates waits a second after opening the connection and before sending this data.

    The Duemilanove contains a trace that can be cut to disable the auto-reset. The pads on either side of the trace can be soldered together to re-enable it. It’s labeled “RESET-EN”. You may also be able to disable the auto-reset by connecting a 110 ohm resistor from 5V to the reset line; see this forum thread for details.

  5. I’m trying to make my Mac to comunicate with arduino thru chars. I only get your app to work when the Arduino IDE’s serial monitor is already opened. I’m on a Intel Mac, Lion OS X and running arduino 1.0 software. The hardware is a Seeeduino. Thank you for your effort!

  6. Hi Phil,

    The problem is the Arduino is operating “too fast” for the serial input data stream so that “Serial.read()” is returning -1 when you do your buffer[i] = Serial.read();. You need to check for -1 every time you do “Serial.read()“, unless you are absolutely sure Serial has all the data you need.

    One way to do this is to wait for the data at every character, like:

      for( int i=1; i< 4; i++) {
        while( !Serial.available() ) ; // wait for data
        buffer[i] = Serial.read();
      }
    

    But that technique will hang waiting for data if none comes.

    If you know exactly how many bytes are being sent, though, the receiving gets easier. For your "hello" example, it can be:

    void loop() {
      if( Serial.available >= 5 ) {  // wait for at least 5 bytes
        for( int i=0; i<5; i++) {
          buffer[i] = Serial.read();
        }
       Serial.println(buffer);
      }
    }
    

    I talk about this in Arduino serial protocol design patterns. Receiving and parsing data on the Arduino is currently a bit messy if the data isn’t a fixed length in size. This will get better soon, as an Arduino update is coming that will have ways of receiving until a newline or other arbitrary character.

  7. After some experimentation I have it somewhat working.

    However, I was expecting my final string to be “hello” but right now it looks like this.

    hÿÿÿ
    eÿÿÿ
    lÿÿÿ
    lÿÿÿ
    oÿÿÿ

    I’m guessing that there is some kind of carriage return or something being sent.

    Here is my code.

    Any ideas?

    Thanks.

    Phil

    char val; // variable to store the data from the serial port
    char buffer[5]; // string array

    void setup() {
    Serial.begin(9600); // connect to the serial port
    }

    void loop () {
    val = Serial.read(); // read the serial port

    if (val > -1) { // check for the start of valid data

    buffer[0] = val; // put the first charcter into the buffer

    for (int i=1; i < 4; i++) { // read 4 more characters

    buffer[i] = Serial.read();
    } // end loop

    Serial.println(buffer);
    } // end if
    }

  8. Hi, this is great and seems to work well for me so far.

    I am wondering what the best way to recompile the data I receive into a string.

    Basically I am using arduino-serial to send text that I want to display on a 16×2 LCD screen hooked up to my arduino.

    If I use “/Applications/arduino-serial -b 9600 -p /dev/tty.usbmodem1d21 -s hello”

    My arduino returns:

    104
    101
    108
    108
    111

    Which is the ascii characters for each of the letters.

    I’m thinking I need some form of array that waits for the first character that is not -1 then stores each character until the next -1

    I am pretty new to Arduino and this seems a little tricky.

    Any advice?

    Thanks.

    Phil

  9. Hi

    I am trying to use:-
    laptop% ./arduino-serial -b 9600 -p /dev/ttyUSB0 -s get -r

    I don’t get back what I expect. Is there an Arduino sketch I can download that is known to work with arduino-serial used in this way?

    Regards

  10. Hello,

    I’m starting an Arduino Project in wich i need to communicate several Arduino boards with one PC via serial port. I know almost nothing about working with serial ports so I’m first learning about it.
    Your code is being really useful for me. Now I’m starting to write a bit of code on my own but using yours as a refference for the “setting the serial connection” part since I’m still getting familiar with this.

    I’ve seen that yor work is under a CC license but I’m not sure about the specifications. Do you allow derived works? Is it OK for you if I publish something of my code based on yours giving recognition to you?

    Thanks,

    Sakul.

  11. I’m trying to send a command to the arduino and get a response but I can’t seem to get it to work:

    command:
    ./arduino-serial -b 9600 -p /dev/ttyUSB0 -d 2000 -s foo -r

    response:
    read: foo

    the response is whatever I tried to send the arduino, my sketch sends different output depending on the command sent.

  12. [SOLVED] I’ve spent over a month trying to have a good communication between linux (Debian Squeeze) and ARDUINO using C programming. I tried every possible configuration with termios.h. My problem was that linux seems to communicate twice at the beginning of the connection with ARDUINO, confusing all the following dialogue. I don’t now why it happens, but finally I’ve found a solution to solve it.

    So, this is the C code to initialize serial connection with ARDUINO using termios.h. If you don’t know how the following functions work, I suggest this link: http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.htmlSo.
    —- Beginning of C code —–

    #include    /* File control definitions */
    #include    /* Error number definitions */
    #include  /*linux serial library*/
    #define DEVICE_ADDR "/dev/ttyACM0"
    
    int main()
    {
     struct termios options;
     fd = open(DEVICE_ADDR, O_RDWR | O_NOCTTY | O_NDELAY);
     if (fd<0) perror("open_port: Unable to open /dev/ttyACM0 - ");
     
     options.c_cflag=6322; //6322 is for BOUDRATE 115200, if you want 9600 use 2237 instead
     options.c_lflag=0;
     options.c_iflag=0;
     options.c_oflag=0;
    
     tcsetattr(fd, TCSANOW, &options);
    
     //the following two lines is the strange thing that makes the whole thing work
     sleep(1); //Sleep time works only from 1 to 2 (2 not included)
     tcflush(fd, TCIFLUSH);
    
    

    — end of C code —

    This is all, from now on you can add your own code to read and write with ARDUINO, using C read and write functions.
    Have a good programming day.

  13. Finally got it resolved, with a lot of help from a friend. We’re using an AppleScript to telnet to ser2sock
    to the Arduino, attached to a remote machine.

    Many thanks,

    Carl

  14. I got the Arduino to respond to this input from Terminal: arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -d 2000 -s b
    but the Arduino LED just flashes 3 times very quickly, regardless of what I have programmed into it’s sketch.

    Any idea what may be going on?

    Thanks,

    Carl

  15. I got the Arduino to respond to this Terminal input: arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -s a
    but the LED just does 3 quick flashes, not what was programmed for the LED to do in the sketch.

    In fact it just flashes the LED regardless of what I send it or what is in the sketch to do.

    Any ideas?

    Carl

Leave a Reply

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