arduino到raspberrypi串口通信

时间:2014-12-25 19:24:09

标签: c++ linux arduino

我一直遇到垃圾字符和通过串口连接传来的奇怪数据的问题我试图在arduino和raspi之间建立。 arduino用于从各种传感器收集数据并将其作为逗号分隔线传输到raspi,每个“帧”一次(不理想,但仍然足以满足我的需求)

在我的windows机器上使用arduino串口时,或者在raspberrypi上使用“sudo screen / dev / ttyACM0 115200,cs8”时,数据很好,所以我有理由相信arduino不是问题

我有以下代码在raspi端建立连接:

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;
}

以下内容应该读取缓冲区中的所有数据:

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;
}

然后在这个循环中处理:(我只使用进入的数据的最后一个“帧”,因为来自arduino的数据比我在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);
}

这里的问题是,当数据被推送到控制台(最后一个代码块中的cout)时,它有时会被破坏。我希望有一系列有序的数据,但有时我会得到奇怪的控制字符,字母,截断的数据行等等。

我感觉它发生在倒数第二个代码块中,我将任何新数据附加到返回字符串,但我不确定是否是这种情况,或者如何修复它。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:0)

确保您的设备使用相同的电压。我使用电平转换器将Arduino连接到Pi,因为Pi是3.3v设备而我的Arduino是5v。

这是电平转换器: http://www.adafruit.com/product/757

答案 1 :(得分:0)

简单的RS232通信不是可靠的通信。即使2个设备正常工作,也可能发生通信错误(因为电线不良,寄生虫......)。您应该添加一种机制,允许您至少检测坏帧(校验和,crc,...)并忽略它们。

答案 2 :(得分:0)

结果是,将检索数据的函数更改为:

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;
}

似乎可以解决问题。不确定它是否理想,但它对我有用。