我正在设置这样的端口:
...
这显然不是最理想的,因为它不会暂停等待字符。
尽管有这种意识,您仍使用并发布此代码?
我怀疑这个 “次优” 代码会在浪费 CPU 周期并消耗进程的时间片的同时轮询系统数据,这是问题的一部分。您尚未发布该问题的完整且最小的示例,我只能部分复制该问题。
在具有两个 USART 的 SBC 上,我有一个程序在串行端口上生成“请求”和“响应”数据。生成程序为:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int main(void)
{
char *masterport = "/dev/ttyS0";
char *slaveport = "/dev/ttyS2";
int mfd;
int sfd;
int wlen;
/* open request generator */
mfd = open(masterport, O_RDWR | O_NOCTTY | O_SYNC);
if (mfd < 0) {
printf("Error opening %s: %s\n", masterport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(mfd, B115200);
/* open response generator */
sfd = open(slaveport, O_RDWR | O_NOCTTY | O_SYNC);
if (sfd < 0) {
printf("Error opening %s: %s\n", slaveport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(sfd, B115200);
/* simple output loop */
do {
wlen = write(mfd, "ABCD", 4);
if (wlen != 4) {
printf("Error from write cmd: %d, %d\n", wlen, errno);
}
tcdrain(mfd); /* delay for output */
wlen = write(sfd, "xy", 2);
if (wlen != 2) {
printf("Error from write resp: %d, %d\n", wlen, errno);
}
tcdrain(sfd); /* delay for output */
} while (1);
}
问题是我遇到了某种缓冲,因为当两个进程在一个紧密的循环中交换数据时,我经常会看到一些请求一起出现,然后是相应的答案
您没有明确您所谓的“紧密循环”,但上述程序将在“请求”后 30 毫秒生成“响应”(由双通道示波器测量) .
顺便说一句,串行终端接口是高度分层的。即使没有 USB 使用的外部总线的开销,至少还有 termios 缓冲区和 tty 翻转缓冲区,以及 DMA 缓冲区。见Linux serial drivers
SBC 的每个 USART 都连接到一个 FTDI USB 到 RS232 转换器(它是旧的四端口转换器的一部分)。请注意,USB 端口速度仅为 USB 1.1。用于串行捕获的主机 PC 是 10 年前运行旧 Ubuntu 发行版的硬件。
尝试复制您的结果:
ABCD
x
y
A
BCD
xy
ABCD
xy
ABCD
xy
A
BCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD
xyxyxyxyxyxyxyxyxyxyxyxyxy
ABCD
xy
ABCD
xy
AB
CD
xy
ABCD
xy
ABCD
xy
AB
CD
xy
ABCD
xy
ABCD
x
y
A
BCD
xy
ABCD
xy
ABCD
x
y
AB
CD
xy
ABCD
xy
ABCD
x
y
只有一次(捕获程序启动后大约 1.5 秒)有一次多写捕获。 (在这种情况发生之前,输出中甚至会出现明显的暂停。)否则,每个读取/捕获都是部分或单个/完整的请求/响应。
使用使用阻塞 I/O 的捕获程序,对于 4 字节的请求消息和 2 字节的响应消息,结果始终是“完美的”。
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
通过将请求的 VMIN=4 和响应的 VMIN=2 更改为所有内容的 VMIN=1 来调整程序,会稍微改变捕获的质量:
ABCD
xy
ABCD
x
ABCD
y
ABCD
xy
ABC
xy
D
x
ABCD
y
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABC
xy
D
x
ABCD
y
虽然会发生部分捕获,但每次读取永远不会有多个“消息”。输出流畅一致,与非阻塞程序一样没有任何停顿。
使用阻塞读取的捕获程序是:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed, int rlen)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = rlen;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int main(void)
{
char *masterport = "/dev/ttyUSB2";
char *slaveport = "/dev/ttyUSB3";
int mfd;
int sfd;
/* open request reader */
mfd = open(masterport, O_RDWR | O_NOCTTY | O_SYNC);
if (mfd < 0) {
printf("Error opening %s: %s\n", masterport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(mfd, B115200, 4);
/* open response reader */
sfd = open(slaveport, O_RDWR | O_NOCTTY | O_SYNC);
if (sfd < 0) {
printf("Error opening %s: %s\n", slaveport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(sfd, B115200, 2);
tcflush(mfd, TCIOFLUSH);
tcflush(sfd, TCIOFLUSH);
/* simple noncanonical input loop */
do {
unsigned char buffer[80];
int rdlen;
rdlen = read(mfd, buffer, sizeof(buffer) - 1);
if (rdlen > 0) {
buffer[rdlen] = 0;
printf("%s\n", buffer);
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Timeout from read\n");
}
rdlen = read(sfd, buffer, sizeof(buffer) - 1);
if (rdlen > 0) {
buffer[rdlen] = 0;
printf("%s\n", buffer);
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Timeout from read\n");
}
} while (1);
}
这实质上是每个串行终端上的双半双工捕获,用于请求-响应对话框。无法准确捕获/显示实际的全双工对话框。
这些使用阻塞读取的结果似乎与其他答案相矛盾,即 USB 串行转换器会将串行数据缓冲并打包成无法识别的字节段。
只有当我使用非阻塞读取时,我才会遇到您报告的“缓冲”。