使用 C++ 从 Linux 串行端口读取会提供混乱的数据
Reading from Linux serial port using C++ provides messy data
所以我有基于Raspberry Pi(Modberry)的嵌入式设备和4个传感器通过一个USB集线器连接。这些传感器一直通过串行端口发送数据,我必须读取和分析这些数据。数据按块划分:每个块 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
问题是错误地打开串行端口。所以我从这个问题中获取了打开代码,现在一切正常:
如何在C语言中从串口打开,读取和写入?
@JD_GRINDER和@sawdust谢谢你们给了我正确的方向!
相关文章:
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 嵌套在类中时无法设置成员数据
- 使用流处理接收到的数据
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在cuda线程之间共享大量常量数据
- C++将文本文件中的数据读取到结构数组中
- 如何在C++中序列化结构数据
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 在c代码之间共享数据的最佳方式
- 链表,反向函数,数据结构
- 数据成员SFINAE的C++17测试:gcc vs clang
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 使用 C++ 从 Linux 串行端口读取会提供混乱的数据
- 堆数据混乱
- Arduino程序读取回混乱的数据
- 什么可能导致数据包的字节顺序部分混乱?
- wchar_t数据从非托管状态混乱到托管状态