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. Logger? I’m not sure to what you’re referring. The “arduino-serial” program isn’t a data logger. It’s not really designed to be run for long durations, just to quickly get a chunk of data from an Arduino and exit.

    However, “arduino-serial” does emit its output on stdout, so it’s output can be redirected to a file as you have done.

    What is this “logger” program you’re running? It’s very clearly not arduino-serial.

  2. the serial logger you have does not output to a text file using >>.
    I have this in my command line logger is the binary output. ./logger>> test.csv is their any way I can make that work? I am using ubuntu.
    Will I have to write more c to open a real file or create one and fprintf to it?

    I have tried your program also it does not print help to the text file ether.

  3. I have just gotten two arduino’s not two pc’s so maby i can make them talk at eatchother. …

  4. I think their is a relationship with the arduino program being on using that com port.
    Also I still have the 1 second light on 1 second light off delay. So I think as that decreses the buffer or lack of buffer in my c program causes problems. I herd somewhere the arduino has a print f buffer in its c code. If that fills up maby that is the problem.

  5. What do you mean by this exactly?
    Do you mean causes the /dev/ttyUSB0 device to disappear from the “/dev/” directory?
    Or do you mean the device is still present, but it cannot be opened?
    Or do you mean the serial port on the Arduino becomes unavailable to the running sketch?

    I have a feeling you are running into buffering issues of either the FTDI chip on the Arduino or the Linux device driver.

    Normally when you’re transmitting so much data at such a high speed, you use the hardware flow control lines so you can pace your transmitting so as not to overflow any buffers. I don’t think the Arduino Serial class gives you access to those lines (or even runs them to the Arduino MCU)

    One way to test if this is an Arduino or PC problem is to have two PCs or two Arduinos, and connect them together, sending data from one and receivin on the other.

  6. things seem to run right 1 time then the port disappears could it not be closing?

    void loop () {
    Serial.println(i++);

    delayMicroseconds(1137);
    if (i > 99){i=0;}
    }

    this runs in arduino ide but the c code causes the port to disapear after 1 run.

  7. 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(115200); // connect to the serial port
    }

    void loop () {
    Serial.print(i++);
    Serial.println(” I”); // print out a hello
    digitalWrite(ledPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(ledPin, LOW);
    delayMicroseconds(500);
    if (i > 255){i=0;}
    }
    seems to do some kind of buffer over flow it turns off /dev/ttyUSB0 and does not let me back in until I restart.
    the directory disapears for my script & arduino ide.

  8. ./arduino-serial -b 9600 -p /dev/ttyUSB0 -r
    is what I try I am using ubuntu and a Boarduino made by adafruit with a 3.. avr.
    read: ? is what I get in return I am realy confused.
    I tried
    ./arduino-serial -b 9600 -p /dev/ttyUSB0 -d 2000-r
    and it worked

  9. Thanks I will try to keep the arduino’s USB0, USB1… streight I will be trying it very soon. I just want to pass my schematics on for checking to the open eeg mailing list then work on that.

  10. Hi josh,
    Have you tried this yet and are having problems, or are you just curious how to go about it? If the latter, then the main thing to look at is the “fd” variable. This is the “file descriptor” of the serial port and is returned by the open() function. It is unique for each serial port opened. And all subsequent functions take an “fd”. So if you take care to keep your “fd”s straight, it should work just fine.

    If you’re running out of pins on your Arduino, I’d recommend picking up an Arduino MEGA. It has tonnes more pins than a regular Arduino.

  11. Hi your code compiled on GCC no problem no warnings etc. Now I will try editing it to just read from 2 arduino’s I have plugged into my laptops 2 serial ports. Then I will try the same thing with a powered hub afterwards.

    This will be at 115200 bits per second.

    Has anyone you know of tried 2 com ports open at once or more?
    Any problems you know of I should be aware of?

    I am working on a data logger the analog and 24 bit analog to digital converter stuff and arduino is coming together nicely.

    I am really interested in Decomposition of EMG signals using arduino’s to shovel data from 4 emg channels to a .csv comma seperated value file or straight to a mysql database for a open source design of this system.

    More channels will be made but 4 is as many as the arduino can shovel so that is why I am testing 2 arduino’s with my data logging setup.

  12. Hi Josh,
    I’m not sure what your shell script is or what the sketch is on your Arduino, so I can’t really help debug your problem. But doing things via the shell isn’t that speedy, and 115200 is pretty speedy.

  13. Hi Jack,
    I’m not quite sure what you mean by the “n 1” and “n 2” are in the above line (do you mean “-n 1” & “-n 2”?), but I think you might need to add a 3-5 second delay, like:

    % ./arduino-serial -b 9600 -p /dev/tty.usbserial -d 5000 ...
    

    This is because opening the serial port to Arduino causes the Arduino to reset and then you have to wait for the bootloader to time out.

  14. Hi I tried the bash script with tail and redirected it to the logging.csv file so I could make a arduino data logger…
    Be forwarned I found the scripts by searching “/dev/ttyUSB0 arduino” the problem is…

    I told arduino to count and output it to the serial port at 115200 bps…
    then told the bash script to open the serial port at 115200 bps.
    then listen to one line of the count and print to the csv file… loop…

    It was missing the same ammount of numbers from the count I think the number was around 20.

    Any ideas? I hope the c program can work ok…
    Any idea on how to open 2 arduinos and log from both of them?

  15. Hello,

    i have this in my .pde (with Arduino) and send this to my microcontroler :


    void loop()
    {
    if (Serial.available() > 0) {
    intervalid = Serial.read();
    if (intervalid==2) {
    intervaldiffuse=Serial.read();
    intervaldiffuse=(intervaldiffuse-3)*60;
    }
    if (intervalid==1) {
    intervalstop=Serial.read();
    intervalstop=(intervalstop-3)*60;
    }
    }

    if (value == LOW) {
    if (millis() – previousMillis > intervalstop) {
    previousMillis = millis();
    value = HIGH;
    }
    }
    if (value == HIGH) {
    if (millis() – previousMillis > intervaldiffuse) {
    previousMillis = millis();
    value = LOW;
    }
    }
    digitalWrite(ledPin, value);
    }

    So, sending something like this with Terminal (MacOSX) :
    arduino-serial -b 9600 -p /dev/tty.usbserial-A6004nYe -n 2 -n 30 n 1 -n 10
    should change the blink of the LED.
    But i need to send this command three times to see its effect.
    the ‘n 1’ is used for ‘if (intervalid==1)’ and the ‘n 2’ for ‘if (intervalid==2)’
    Any idea about my problem ?
    Thanx a lot for your job.
    ++

    Jack

  16. Hi,

    I use the following command in linux to read my arduino board.
    “cat < /dev/ttyUSB0”
    and
    “cat filename” to capture the output to a file.

    Regards Stan

  17. Todd,

    The mailman just brought my new Duemilanove, and my first download was “blink”, of course.

    I was looking for something else to try quick, and found your serial_read_blink.

    I just used hyperterm. After seeing “Blink!”

    I tried changing:
    Serial.println(“blink!”);
    to Serial.println(i); to see it count up, then
    Serial.println(val-i) to see it count down.

    Thanks for these examples!

  18. Tom Morgan AND Todbot:

    I downloaded Cygwin but I do not understand what you did to get the dll file in that folder. Step by step maybe?

    I am on this path again because I worked for a long time using other methods for windows which were unsuccessful but this code above works fine in posix machines

Leave a Reply

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