使用C ++从Linux串行端口读取会产生混乱的数据

时间:2019-04-22 16:31:04

标签: c++ linux raspberry-pi serial-port

因此,我有一个基于Raspberry Pi(Modberry)的嵌入式设备和通过一个USB集线器连接的4个传感器。这些传感器始终通过串行端口发送数据,我必须对其进行读取和分析。数据按块划分:每个块7个字节,并在它们之间留有空间。前4个字节是时间,3个字节是传感器测量的值。正常值应该约为0 +-5。波特率是921600。当我仅读取一个传感器(例如“ / dev / ttyUSB0”)时,一切都很好,但是当我开始增加可读性的传感器数量时,情况就完全错了。代表时间的4个字节始终以正确的方式传递,并且永远不会出错,但是后3个字节的99%的时间带有奇怪的值并开始发送垃圾邮件,如下所示:

[2019-04-22 17:48:02.264] Device: /dev/ttyUSB3, Time: 12226408, Value: 1690
[2019-04-22 17:48:02.265] Device: /dev/ttyUSB2, Time: 12217312, Value: 1690
[2019-04-22 17:48:02.265] Device: /dev/ttyUSB2, Time: 12217316, Value: 1690

有趣的是,重启应用程序后不会100%发生这种情况,而是大约80%。

我也用Python和Java制作了一个没有此问题的应用程序。它们都在同一设备上运行。我试图在单独的线程中读取每个传感器,但这也无济于事。

我大大简化了代码,并删除了该块中的所有错误检查。

void openSerial()
{
const int fileDescriptor = ::open(mParams.path.c_str(), O_RDONLY | O_NOCTTY);
termios SerialPortSettings;

SerialPortSettings.c_cflag &= ~PARENB;
SerialPortSettings.c_cflag &= ~CSTOPB;
SerialPortSettings.c_cflag &= ~CSIZE;
SerialPortSettings.c_cflag |= CS8;
SerialPortSettings.c_cflag &= ~CRTSCTS;
SerialPortSettings.c_cflag |= CREAD | CLOCAL;
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
SerialPortSettings.c_oflag &= ~OPOST;
SerialPortSettings.c_cc[VMIN] = 10;
SerialPortSettings.c_cc[VTIME] = 0;

cfsetispeed(&SerialPortSettings, 921600);
tcsetattr(fileDescriptor, TCSANOW, &SerialPortSettings);
tcflush(fileDescriptor, TCIOFLUSH);
}

static const int BUFFER_SIZE = 256;
void readSerial()
{
    char buffer[BUFFER_SIZE + 1] = { 0 };
    int count = 0;

    count = read(mfd, buffer, BUFFER_SIZE);

    std::vector<char> rawBuffer;
    for (int i = 0; i < count; i++) {
        rawBuffer.push_back(buffer[i]);
    }

    parse(rawBuffer);
}

void parse(std::vector<char> rawBuffer)
{
    auto currentSpace = std::find(rawBuffer.begin(), rawBuffer.end(), ' ');
    auto nextSpace = std::find(currentSpace + 1, rawBuffer.end(), ' ');
    size_t counter = 0;
    while (currentSpace != rawBuffer.end()) {
        const int dist = std::distance(currentSpace, nextSpace);

        if (dist == 8) {
            XD1000Data data;
            data.time = parseTime(&(*(currentSpace + TIME_SHIFT)));
            data.value = parseValue(&(*(currentSpace + VALUE_SHIFT)));
        } else {
                printf("packet size error, dist %d, rawBuffer.size %d, counter %d", dist, rawBuffer.size(), counter);
        }
        counter++;
        currentSpace = nextSpace;
        nextSpace = std::find(currentSpace + 1, rawBuffer.end(), ' ');
    }

    rawBuffer.clear();
}

long parseTime(char *buffer)
{
    long dest[4];
    long time;

    parseBuffer<long, 4>(buffer, dest);

    time = dest[3] + (dest[2] << 6) + (dest[1] << 12) + (dest[0] << 18);

    return time;
}

int parseValue(char *buffer)
{
    int dest[3];
    int value;

    parseBuffer<int, 3>(buffer, dest);

    value = dest[2] + (dest[1] << 6) + (dest[0] << 12);

    return (short)((value & 0x1000) ? (value | 0xf000) : (value & 0x0fff));
}

template <typename T, size_t size> void parseBuffer(char *buffer, T *dest)
{
    for (size_t i = 0; i < size; i++) {
        if (isupper(buffer[i]))
            dest[i] = buffer[i] - 'A';
        else if (islower(buffer[i]))
            dest[i] = buffer[i] - 'a' + 26;
        else if (isdigit(buffer[i]))
            dest[i] = buffer[i] - '0' + 52;
        else if (buffer[i] == '+')
            dest[i] = 62;
        else if (buffer[i] == '/')
            dest[i] = 63;
        else // error
            ;
    }
}

我100%确保传感器未发送此1690数据,在任何其他具有传感器数量甚至Minicom的应用程序中均未观察到此行为。这是它应该实际工作的方式,它确实很少见:

Device:/dev/ttyUSB3 14006188 -5
Device:/dev/ttyUSB3 14006192 -6
Device:/dev/ttyUSB3 14006196 -5
Device:/dev/ttyUSB3 14006200 -6
Device:/dev/ttyUSB3 14006204 -5
Device:/dev/ttyUSB3 14006208 -6
Device:/dev/ttyUSB3 14006212 -5
Device:/dev/ttyUSB0 14006152 -1
Device:/dev/ttyUSB0 14006156 -2
Device:/dev/ttyUSB0 14006160 -1
Device:/dev/ttyUSB0 14006164 0

1 个答案:

答案 0 :(得分:0)

问题是打开串行端口的方式错误。因此,我从这个问题中获取了开放代码,现在一切正常:

How to open, read, and write from serial port in C?

谢谢@JD_GRINDER和@sawdust给我正确的指导!