I programmed the Arduino to wait until it receives a byte from the PC and then transmit “Hello” back. The (super simple) Arduino sketch is here: https://gist.github.com/2980344
I’m frustrated with the WordPress code posting functionality, so I put the program that does the reading to and receiving from the Arduino on Github. It’s called Canonical Arduino Read.
Here’s a breakdown of the important bits:
/* open serial port */ fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY); printf("fd opened as %i\n", fd); /* wait for the Arduino to reboot */ usleep(3500000);
As I’ve said before, you have to give the Arduino some time to reboot after you call open(). Notice that I’m opening this as a blocking port by leaving out O_NDELAY as an option.
/* get current serial port settings */ tcgetattr(fd, &toptions); /* set 9600 baud both ways */ cfsetispeed(&toptions, B9600); cfsetospeed(&toptions, B9600); /* 8 bits, no parity, no stop bits */ toptions.c_cflag &= ~PARENB; toptions.c_cflag &= ~CSTOPB; toptions.c_cflag &= ~CSIZE; toptions.c_cflag |= CS8; /* Canonical mode */ toptions.c_lflag |= ICANON; /* commit the serial port settings */ tcsetattr(fd, TCSANOW, &toptions);
Nothing fancy here. I’m getting the current port configuration, setting the input/output speed to 9600 baud, setting the data expectations to be 8 bits per word, with no parity bit and no stop bit, setting canonical mode, and then committing those changes back to the serial port.
My past few posts have been about trouble I’ve had reading data, and the fixes were all in the code above that determines the serial port settings. I accidentally (by virtue of a sloppy copy/paste of another program I wrote) had “&= CS8” instead of “|=CS8”. That was dumb mistake number one. Number two was that I was setting c_iflag to ICANON instead of c_lflag. That’s a TOUGH typo to catch.
/* Send byte to trigger Arduino to send string back */ write(fd, "0", 1); /* Receive string from Arduino */ n = read(fd, buf, 64); /* insert terminating zero in the string */ buf[n] = 0; printf("%i bytes read, buffer contains: %s\n", n, buf);
This last part of the program writes out one byte to the Arduino. The Arduino sees this, and then writes back “Hello”. I read that “Hello” into my buf array, and then terminate that array with 0 so that when I use printf() on the next line it doesn’t go into undefined parts of the array.
And that’s that. I started working on this as part of a larger project on Thursday. It’s Sunday evening now and I finally got this one part working perfectly. I don’t regret getting so stuck. I’ve had to really dig into the terminal interface and I feel much more confident with it now. Now that this chunk of code is working, I’ll fit it into the larger program.
The larger program will query the Arduino, and the Arduino will send back a voltage read from a temperature sensor. Super similar to what I’m doing above, which queries the Arduino (by sending it a byte) and gets serial data back. The next hump will be figuring out how to convert the string sent back into a numeric type like float or int. I don’t recall Unix having a standard ascii-to-int function. No doubt this is a solved problem, so I won’t have to search too hard to find a solution.
Leave a comment below or shoot me a message on Twitter @cheydrick if you have questions!