如何同步接收串口数据?
How to recieve data on serial port synchronously?
我有以下设置:运行 Linux (TCL) 的计算机和以固定频率 (100 Hz) 发送固定长度(10 字节)数据包的设备。
在计算机上,我打开了那个串口,我正在尝试读取传入的数据。但是,不是一直以 10 字节的块接收它,而是读取的数据量较少,我不得不将它们重新组装回去。
我的目标是在每个数据包到达后发送响应,尽可能保持数据包之间的间隔。
这是我打开串口的方式:
int fd = open(device_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd == -1)
{
LOGPRINT("Failed to open terminal file.\nError #%d (%s)\n",
errno, strerror(errno));
return fd;
}
LOGPRINT("Setting terminal attributes\n");
struct termios config;
struct termios *pterm = &config;
// set baud rate
LOGPRINT("Setting baud rate to %d.\n", baud_rates[baud_rate_index]);
// change to raw mode
LOGPRINT("Setting terminal to raw mode\n");
pterm->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
| IGNCR | ICRNL | IXON);
pterm->c_oflag &= OPOST;
pterm->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
cfsetispeed(pterm, baud_bits[pconfig->baud_rate_index]);
cfsetospeed(pterm, baud_bits[pconfig->baud_rate_index]);
LOGPRINT("Set character size, parity and stop bit flags.\n");
// set character size
pterm->c_cflag &= ~CSIZE;
pterm->c_cflag |= csize_flag;
// set parity
pterm->c_cflag &= ~(PARENB | PARODD);
pterm->c_cflag |= parity_flag;
// set stopbits
pterm->c_cflag &= ~CSTOPB;
pterm->c_cflag |= stopbits_flag;
// enable reading; ignore control lines
pterm->c_cflag |= CREAD | CLOCAL;
// disable flow control
pterm->c_cc[VMIN] = 1;
pterm->c_cc[VTIME] = 0;
LOGPRINT("Flush terminal.\n");
// flush terminal
tcflush(fd, TCIOFLUSH);
LOGPRINT("Apply parameters.\n");
return WRAPSYSCALL(tcsetattr(fd, TCSANOW, pterm));
此外,我使用 fnctl 在文件描述符上设置了以下内容:
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC | O_DIRECT);
我在一个循环中读取文件描述符,select()
调用包含 fd
的文件描述符集,然后读取所有可用字节(请求的字节数远大于 10)。
我应该更改什么以确保传入的数据在正确及时地处理?
如果您的程序除了等待字节和应答之外什么都不做,那么您可以尝试使用阻塞文件操作。从 open
函数调用中删除 O_NONBLOCK
标志,并在设置端口后执行 read(fd, buffer, 10)
。该函数将在恰好读取 10 个字节(或发生错误或信号到达)后 return。
但是,请记住,您可以在数据包传输的中间开始读取操作,例如,您可以获得第 n 个数据包的最后 x 个字节和第 n+1 个数据包的前 10-x 个字节。
我有以下设置:运行 Linux (TCL) 的计算机和以固定频率 (100 Hz) 发送固定长度(10 字节)数据包的设备。
在计算机上,我打开了那个串口,我正在尝试读取传入的数据。但是,不是一直以 10 字节的块接收它,而是读取的数据量较少,我不得不将它们重新组装回去。
我的目标是在每个数据包到达后发送响应,尽可能保持数据包之间的间隔。
这是我打开串口的方式:
int fd = open(device_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd == -1)
{
LOGPRINT("Failed to open terminal file.\nError #%d (%s)\n",
errno, strerror(errno));
return fd;
}
LOGPRINT("Setting terminal attributes\n");
struct termios config;
struct termios *pterm = &config;
// set baud rate
LOGPRINT("Setting baud rate to %d.\n", baud_rates[baud_rate_index]);
// change to raw mode
LOGPRINT("Setting terminal to raw mode\n");
pterm->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
| IGNCR | ICRNL | IXON);
pterm->c_oflag &= OPOST;
pterm->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
cfsetispeed(pterm, baud_bits[pconfig->baud_rate_index]);
cfsetospeed(pterm, baud_bits[pconfig->baud_rate_index]);
LOGPRINT("Set character size, parity and stop bit flags.\n");
// set character size
pterm->c_cflag &= ~CSIZE;
pterm->c_cflag |= csize_flag;
// set parity
pterm->c_cflag &= ~(PARENB | PARODD);
pterm->c_cflag |= parity_flag;
// set stopbits
pterm->c_cflag &= ~CSTOPB;
pterm->c_cflag |= stopbits_flag;
// enable reading; ignore control lines
pterm->c_cflag |= CREAD | CLOCAL;
// disable flow control
pterm->c_cc[VMIN] = 1;
pterm->c_cc[VTIME] = 0;
LOGPRINT("Flush terminal.\n");
// flush terminal
tcflush(fd, TCIOFLUSH);
LOGPRINT("Apply parameters.\n");
return WRAPSYSCALL(tcsetattr(fd, TCSANOW, pterm));
此外,我使用 fnctl 在文件描述符上设置了以下内容:
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC | O_DIRECT);
我在一个循环中读取文件描述符,select()
调用包含 fd
的文件描述符集,然后读取所有可用字节(请求的字节数远大于 10)。
我应该更改什么以确保传入的数据在正确及时地处理?
如果您的程序除了等待字节和应答之外什么都不做,那么您可以尝试使用阻塞文件操作。从 open
函数调用中删除 O_NONBLOCK
标志,并在设置端口后执行 read(fd, buffer, 10)
。该函数将在恰好读取 10 个字节(或发生错误或信号到达)后 return。
但是,请记住,您可以在数据包传输的中间开始读取操作,例如,您可以获得第 n 个数据包的最后 x 个字节和第 n+1 个数据包的前 10-x 个字节。