【发布时间】:2021-05-26 12:19:26
【问题描述】:
我在 STM32 和 Linux 计算机之间进行了串行通信。 STM 每 10ms 传输 6 个字节的数据“iiiiiiC”(i = transmission_counter % 10, C = character 'C')。 然而,接收器没有特定的迭代时间,读取串行的速度可能快于或慢于 10 毫秒。另外,读取函数应该是非阻塞的。
这意味着有时会收到数据:
RD = '111'
RD = '11C2'
RD = '222'
RD = '2C33'
我想要 usable_data = 22222C
有时:
RD = '333C44444C'
RD = '55555C66666'
RD = 'C77777C8888'
我想要 usable_data = 77777C
代码类似如下:
int main() {
int serial_port = open("/dev/ttyACM1", O_RDWR);
struct termios tty;
// Read in existing settings, and handle any error
if(tcgetattr(serial_port, &tty) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
return 1;
}
tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size
tty.c_cflag |= CS8; // 8 bits per byte (most common)
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
tty.c_lflag &= ~ICANON;
tty.c_lflag &= ~ECHO; // Disable echo
tty.c_lflag &= ~ECHOE; // Disable erasure
tty.c_lflag &= ~ECHONL; // Disable new-line echo
tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes
tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
// tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX)
// tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX)
tty.c_cc[VTIME] = 0; // No blocking, return immediately with what is available
tty.c_cc[VMIN] = 0;
cfsetispeed(&tty, B115200);
cfsetospeed(&tty, B115200);
// Save tty settings, also checking for error
if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
return 1;
}
while (1){
char read_buf [100]; // Large serial buffer so even if the receiver is slow the most recent data will be in this array
memset(&read_buf, '\0', sizeof(read_buf));
int num_bytes = read(serial_port, &read_buf, sizeof(read_buf));
std::cout << num_bytes << " " << read_buf << std::endl;;
... unknown time ahead ...
}
close(serial_port);
return 0; // success
}
我尝试了一些解决方法,但它们并没有解决所有问题,或者我对它们不满意:
// For cases where receiver is slow and receives more than one complete message at once
char part [6];
uint16_t index = 0;
for (index; index < 6; index++){
if (read_buf[index] == 'C'){
while (read_buf[index] == 'C'){
index += 6;
}
index -= 6;
break;
}
}
memcpy(part, read_buf + index - 5, 6);
.
// For cases where received data does not fit into read_buffer, i.e. we are reading old data - flush it.
int num_bytes = read(serial_port, &read_buf, sizeof(read_buf));
while (num_bytes == sizeof(read_buf)){
num_bytes = read(serial_port, &read_buf, sizeof(read_buf));
}
.
// For cases where received data is out of phase (message does not end with a 'C'). Reads one character at a time until message ends with 'C'. Has many problems.
if (read_buf[sizeof(read_buf)-1] != 'C'){
read(serial_port, &read_buf, 1);
}
【问题讨论】:
-
这能回答你的问题吗? Non-blocking call for reading descriptor
-
@Frank 不是真的,我想。我正在寻找一种从接收到的数据中获取 usable_data 的方法,但是由于 usable_data 可能会被拆分为多个部分(当前消息中的一部分 usable_data,前一个消息中的一部分),因此很难将正确的字节合并在一起。跨度>
-
你必须写一个parser,它会解析数据并提取你感兴趣的部分。
std::cout <<这是stm32吗,我非常喜欢 i> 怀疑你会想要使用 iostream。 -
好吧,
while (num_bytes == sizeof(read_buf))- 每次阅读时都必须“添加”到 num_bytes。 -
@KamilCuk 谢谢,我会试试我写解析器的运气。 iostream 是临时的,仅用于调试。与 STM32 的通信是使用 write(serialport...)。
标签: c++ parsing serial-communication