0
votes

I'vve been having a problem with garbage characters and strange data coming through a serial connection I'm trying to set up between an arduino and a raspi. The arduino is used to gather data from various sensors and transmits it to the raspi as a comma separated line, once per "frame" (not ideal, but still more than fast enough for my needs)

When using the arduino serial interface on my windows machine, or when using "sudo screen /dev/ttyACM0 115200,cs8" on the raspberrypi, the data comes through fine, so I am reasonably sure that the arduino is not the problem.

I have the following code to make a connection on the raspi side:

int serial::openPort(std::string portName)
{
    int serialPort;

    serialPort = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);

    if (serialPort == -1)
    {
        std::cout << "open_port: Unable to open " << portName;
    }
    else
    {
        struct termios portOptions;

        //set up the port so reading nothing returns immediately, instead of blocking
        fcntl(serialPort, F_SETFL, FNDELAY);

        // Fetch the current port settings
        tcgetattr(serialPort, &portOptions);

        // Flush the port's buffers (in and out) before we start using it
        tcflush(serialPort, TCIOFLUSH);

        // Set the input and output baud rates
        cfsetispeed(&portOptions, B115200);
        cfsetospeed(&portOptions, B115200);

        // c_cflag contains a few important things- CLOCAL and CREAD, to prevent
        //   this program from "owning" the port and to enable receipt of data.
        //   Also, it holds the settings for number of data bits, parity, stop bits,
        //   and hardware flow control. 
        portOptions.c_cflag |= CLOCAL;
        portOptions.c_cflag |= CREAD;
        // Set up the frame information.
        portOptions.c_cflag &= ~PARENB;
        portOptions.c_cflag &= ~CSTOPB;
        portOptions.c_cflag &= ~CSIZE;
        portOptions.c_cflag |= CS8;

        // Now that we've populated our options structure, let's push it back to the
        //   system.
        tcsetattr(serialPort, TCSANOW, &portOptions);

        // Flush the buffer one more time.
        tcflush(serialPort, TCIOFLUSH);
    }

    return serialPort;
}

And the following should read all of the data in the buffer:

std::string serial::readData(int serialPort)
{
    char buffer[64];
    int bytesRead = 0;
    std::string returnString;

    do
    {
        bytesRead = read(serialPort, buffer, sizeof(buffer));

        if(bytesRead > 0)
            returnString.append(buffer, bytesRead);

    } while (bytesRead == sizeof(buffer));

    return returnString;
}

which is then processed in this loop: (I am only using the last "frame" of data that is coming in, because the data from the arduino comes in much faster than I can display it on the raspi)

gaugeDataBuffer += serial::readData(port);

std::cout << gaugeDataBuffer;

while(true)
{
    newLineLocation = gaugeDataBuffer.find("\r\n");

    if (newLineLocation == std::string::npos)
        break;

    gaugeDataStrings = utility::split(gaugeDataBuffer.substr(0, newLineLocation), ',');
    gaugeDataBuffer = gaugeDataBuffer.substr(newLineLocation + 2);
}

The problem here, is when the data gets pushed to the console (the cout in the last code block), it is sometimes mangled. I would expect a nice orderly series of lines of data, but sometimes I get strange control characters, letters, data lines that are truncated, etc.

I have a feeling that it is happening in the second to last code block, where I am appending any new data to the returnstring, but am unsure if that is the case, or how to fix it.

Any help would be greatly appreciated.

3
I'd suppose the serial ports are properly synchronized by the actual baud rate?πάντα ῥεῖ
Both the arduino and the raspi are using baud rate 115200, and should be set up as 8N1. I am mildly unsure as to whether that is true for the raspi side, but everything I've read seems to say im doing it right.Patrick
Try lower baud-rates maybe.πάντα ῥεῖ
oddly, the only one that works in the arduino software is 115200, all of the others result in garbage. (yes I am changing it in the serial monitor as well as the arduino code.)Patrick

3 Answers

0
votes

Make sure your devices are talking the same voltage. I serially interfaced an Arduino to a Pi with a level converter, because the Pi is a 3.3v device and my Arduino is a 5v.

Here is the level converter: http://www.adafruit.com/product/757

0
votes

so as it turns out, changing the function that retrieves the data to this:

std::string serial::readData(int serialPort)
{
    char buffer[1];
    int bytesRead = 0;
    std::string returnString;

    do
    {
        bytesRead = read(serialPort, buffer, 1);

        if(bytesRead > 0)
        {
            returnString += buffer[0];
        }

    } while (bytesRead == sizeof(buffer));

    return returnString;
}

appears to fix the problem. Not sure if its ideal, but it works for me.

0
votes

A simple RS232 communication is not a reliable communication. Even if the 2 devices are working properly, communication error could occur (because of poor wires, parasites, ...). You should add a mechanism, that allows you to, at least, detect bad frames (checksum, crc, ...) and ignore them.