使用终端的规范串行读取失败?
Canonical serial reading using terminos fail?
我正在尝试使用串行读取来自我的 arduino 的数据行。
我的arduino代码是这样的:Serial3.print(Z, 2);Serial3.print(F(";"));Serial3.println(F("END\n"));
这是我读取 ubuntu 上的数据的代码:
void setup(){
//set up serial
tcgetattr(dueSerial, &port_options); // Get the current attributes of the Serial port
dueSerial = open("/dev/ttyUSB0", O_RDWR | O_NONBLOCK | O_NOCTTY | O_NDELAY);
if (dueSerial == -1) {
reportFailure("Could not open Arduino");
} else {
port_options.c_cflag &= ~PARENB; // Disables the Parity Enable bit(PARENB),So No Parity
port_options.c_cflag &= ~CSTOPB; // CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit
port_options.c_cflag &= ~CSIZE; // Clears the mask for setting the data size
port_options.c_cflag |= CS8; // Set the data bits = 8
port_options.c_cflag &= ~CRTSCTS; // No Hardware flow Control
port_options.c_cflag |= (CREAD | CLOCAL); // Enable receiver,Ignore Modem Control lines
port_options.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable XON/XOFF flow control both input & output
port_options.c_lflag &= ~(ECHO | ECHONL | IEXTEN | ISIG); // no echo
port_options.c_iflag |= ICANON; //Enable canonical
port_options.c_iflag |= ICRNL; //map CR to NL
//port_options.c_oflag &= ~OPOST; // No Output Processing
//port_options.c_lflag = 0; // enable raw input instead of canonical,
/*
initialize all control characters
default values can be found in /usr/include/termios.h, and are given
in the comments, but we don't need them here
*/
port_options.c_cc[VINTR] = 0; /* Ctrl-c */
port_options.c_cc[VQUIT] = 0; /* Ctrl-\ */
port_options.c_cc[VERASE] = 0; /* del */
port_options.c_cc[VKILL] = 0; /* @ */
port_options.c_cc[VEOF] = 4; /* Ctrl-d */
port_options.c_cc[VTIME] = 0; /* inter-character timer unused */
port_options.c_cc[VMIN] = 0; /* blocking read until 1 character arrives */
port_options.c_cc[VSWTC] = 0; /* '[=10=]' */
port_options.c_cc[VSTART] = 0; /* Ctrl-q */
port_options.c_cc[VSTOP] = 0; /* Ctrl-s */
port_options.c_cc[VSUSP] = 0; /* Ctrl-z */
port_options.c_cc[VEOL] = 0; /* '[=10=]' */
port_options.c_cc[VREPRINT] = 0; /* Ctrl-r */
port_options.c_cc[VDISCARD] = 0; /* Ctrl-u */
port_options.c_cc[VWERASE] = 0; /* Ctrl-w */
port_options.c_cc[VLNEXT] = 0; /* Ctrl-v */
port_options.c_cc[VEOL2] = 0; /* '[=10=]' */
cfsetispeed( & port_options, BAUDRATE); // Set Read Speed
cfsetospeed( & port_options, BAUDRATE); // Set Write Speed
tcflush(dueSerial, TCIFLUSH);
tcflush(dueSerial, TCIOFLUSH);
int att = tcsetattr(dueSerial, TCSANOW, & port_options);
if (att != 0) {
reportFailure("ERROR in Setting Arduino port attributes");
} else {
LOG_INFO("SERIAL DUE Port Good to Go");
}
}
}
void UART::tick() {
//Arduino msg = "IMU;LAX;LAY;LAZ;AVX;AVY;AVZ;AY;AP;AR;END"
// rx_buffer[0] = '0';
memset(&rx_buffer, '[=10=]', sizeof(rx_buffer));
// tcflush(dueSerial, TCIOFLUSH);
rx_length = read(dueSerial, &rx_buffer,255);
if (rx_length < 0) {
LOG_INFO("Error reading");
}else{
LOG_INFO("Read %i bytes. Received message: %s", rx_length, rx_buffer);
}
}
但是当我尝试这段代码时,我一次得到很多行,所以我的输出看起来像这样:
2020-11-15 09:13:09.491 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 0 bytes. Received message:
2020-11-15 09:13:09.496 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 255 bytes. Received message: 0.01;0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;0.03;0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;0.03;0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;-0.02;0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;-0.02;-0.00;0.00;0.00;0.00;0.00;
2020-11-15 09:13:09.501 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 241 bytes. Received message: 0.00;END
IMU;-0.01;-0.02;-0.01;-0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;-0.01;-0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;0.03;-0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;0.03;0.00;0.00;0.00;0.00;0.00;0.00;END
2020-11-15 09:13:09.506 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 0 bytes. Received message:
2020-11-15 09:13:09.511 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 0 bytes. Received message:
但我希望它在每次 read() 函数调用时只读取一行。
我相信我要么设置了一个错误的参数,使 conanical 模式未被使用,要么它忽略了我的 \n 和 \r 但不知道为什么....
请帮我找出原因。
非常感谢!
But I want it to read only one line per read() function call. I believe that I either set a wrong parameter making the conanical mode unused ...
您的程序没有按预期运行,因为规范模式从未真正设置过。
语句
port_options.c_iflag |= ICANON; //Enable canonical
不正确。 ICANON
在 c_lflag
成员中,而不在 c_iflag
.
中
您的代码还有其他问题。
(1)变量dueSerial
未初始化使用:
void setup(){
//set up serial
tcgetattr(dueSerial, &port_options); // Get the current attributes of the Serial port
dueSerial = open(...);
...
需要先获取并验证文件描述符,然后才能在 tcgetattr() 调用中使用。
语句的正确顺序是:
void setup(){
//set up serial
dueSerial = open(...);
if (dueSerial == -1) {
/* abort */
}
tcgetattr(dueSerial, &port_options);
...
(2) 在您的 termios 初始化中未指定大量输入转换。
规范模式启用各种选项来转换某些输入字符,并且大多数这些选项需要被禁用才能被程序读取(相对于交互式终端)。
通常 INPCK
(启用输入奇偶校验)、IUCLC
(将大写字符映射为小写)和 IMAXBEL
(输入队列已满时响铃)被禁用。
您需要检查是否还需要 IGNCR
(保留或忽略回车符 return)、INLCR
(将换行符转换为回车符 return)和 ICRNL
(翻译carriage return to newline unless IGNCR
is set) 也被禁用。
(3) 非阻塞模式的使用值得怀疑。
由于您希望 "每次 read() 函数调用只读取一行",因此阻塞模式是获得该结果的正确方法。
如果您坚持使用非阻塞模式,那么 read() 系统调用将始终 return “立即”并且可能 return 根本没有任何数据。
我正在尝试使用串行读取来自我的 arduino 的数据行。
我的arduino代码是这样的:Serial3.print(Z, 2);Serial3.print(F(";"));Serial3.println(F("END\n"));
这是我读取 ubuntu 上的数据的代码:
void setup(){
//set up serial
tcgetattr(dueSerial, &port_options); // Get the current attributes of the Serial port
dueSerial = open("/dev/ttyUSB0", O_RDWR | O_NONBLOCK | O_NOCTTY | O_NDELAY);
if (dueSerial == -1) {
reportFailure("Could not open Arduino");
} else {
port_options.c_cflag &= ~PARENB; // Disables the Parity Enable bit(PARENB),So No Parity
port_options.c_cflag &= ~CSTOPB; // CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit
port_options.c_cflag &= ~CSIZE; // Clears the mask for setting the data size
port_options.c_cflag |= CS8; // Set the data bits = 8
port_options.c_cflag &= ~CRTSCTS; // No Hardware flow Control
port_options.c_cflag |= (CREAD | CLOCAL); // Enable receiver,Ignore Modem Control lines
port_options.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable XON/XOFF flow control both input & output
port_options.c_lflag &= ~(ECHO | ECHONL | IEXTEN | ISIG); // no echo
port_options.c_iflag |= ICANON; //Enable canonical
port_options.c_iflag |= ICRNL; //map CR to NL
//port_options.c_oflag &= ~OPOST; // No Output Processing
//port_options.c_lflag = 0; // enable raw input instead of canonical,
/*
initialize all control characters
default values can be found in /usr/include/termios.h, and are given
in the comments, but we don't need them here
*/
port_options.c_cc[VINTR] = 0; /* Ctrl-c */
port_options.c_cc[VQUIT] = 0; /* Ctrl-\ */
port_options.c_cc[VERASE] = 0; /* del */
port_options.c_cc[VKILL] = 0; /* @ */
port_options.c_cc[VEOF] = 4; /* Ctrl-d */
port_options.c_cc[VTIME] = 0; /* inter-character timer unused */
port_options.c_cc[VMIN] = 0; /* blocking read until 1 character arrives */
port_options.c_cc[VSWTC] = 0; /* '[=10=]' */
port_options.c_cc[VSTART] = 0; /* Ctrl-q */
port_options.c_cc[VSTOP] = 0; /* Ctrl-s */
port_options.c_cc[VSUSP] = 0; /* Ctrl-z */
port_options.c_cc[VEOL] = 0; /* '[=10=]' */
port_options.c_cc[VREPRINT] = 0; /* Ctrl-r */
port_options.c_cc[VDISCARD] = 0; /* Ctrl-u */
port_options.c_cc[VWERASE] = 0; /* Ctrl-w */
port_options.c_cc[VLNEXT] = 0; /* Ctrl-v */
port_options.c_cc[VEOL2] = 0; /* '[=10=]' */
cfsetispeed( & port_options, BAUDRATE); // Set Read Speed
cfsetospeed( & port_options, BAUDRATE); // Set Write Speed
tcflush(dueSerial, TCIFLUSH);
tcflush(dueSerial, TCIOFLUSH);
int att = tcsetattr(dueSerial, TCSANOW, & port_options);
if (att != 0) {
reportFailure("ERROR in Setting Arduino port attributes");
} else {
LOG_INFO("SERIAL DUE Port Good to Go");
}
}
}
void UART::tick() {
//Arduino msg = "IMU;LAX;LAY;LAZ;AVX;AVY;AVZ;AY;AP;AR;END"
// rx_buffer[0] = '0';
memset(&rx_buffer, '[=10=]', sizeof(rx_buffer));
// tcflush(dueSerial, TCIOFLUSH);
rx_length = read(dueSerial, &rx_buffer,255);
if (rx_length < 0) {
LOG_INFO("Error reading");
}else{
LOG_INFO("Read %i bytes. Received message: %s", rx_length, rx_buffer);
}
}
但是当我尝试这段代码时,我一次得到很多行,所以我的输出看起来像这样:
2020-11-15 09:13:09.491 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 0 bytes. Received message:
2020-11-15 09:13:09.496 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 255 bytes. Received message: 0.01;0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;0.03;0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;0.03;0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;-0.02;0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;-0.02;-0.00;0.00;0.00;0.00;0.00;
2020-11-15 09:13:09.501 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 241 bytes. Received message: 0.00;END
IMU;-0.01;-0.02;-0.01;-0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;-0.01;-0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;0.03;-0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;0.03;0.00;0.00;0.00;0.00;0.00;0.00;END
2020-11-15 09:13:09.506 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 0 bytes. Received message:
2020-11-15 09:13:09.511 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp@87: Read 0 bytes. Received message:
但我希望它在每次 read() 函数调用时只读取一行。 我相信我要么设置了一个错误的参数,使 conanical 模式未被使用,要么它忽略了我的 \n 和 \r 但不知道为什么....
请帮我找出原因。 非常感谢!
But I want it to read only one line per read() function call. I believe that I either set a wrong parameter making the conanical mode unused ...
您的程序没有按预期运行,因为规范模式从未真正设置过。
语句
port_options.c_iflag |= ICANON; //Enable canonical
不正确。 ICANON
在 c_lflag
成员中,而不在 c_iflag
.
您的代码还有其他问题。
(1)变量dueSerial
未初始化使用:
void setup(){
//set up serial
tcgetattr(dueSerial, &port_options); // Get the current attributes of the Serial port
dueSerial = open(...);
...
需要先获取并验证文件描述符,然后才能在 tcgetattr() 调用中使用。
语句的正确顺序是:
void setup(){
//set up serial
dueSerial = open(...);
if (dueSerial == -1) {
/* abort */
}
tcgetattr(dueSerial, &port_options);
...
(2) 在您的 termios 初始化中未指定大量输入转换。
规范模式启用各种选项来转换某些输入字符,并且大多数这些选项需要被禁用才能被程序读取(相对于交互式终端)。
通常 INPCK
(启用输入奇偶校验)、IUCLC
(将大写字符映射为小写)和 IMAXBEL
(输入队列已满时响铃)被禁用。
您需要检查是否还需要 IGNCR
(保留或忽略回车符 return)、INLCR
(将换行符转换为回车符 return)和 ICRNL
(翻译carriage return to newline unless IGNCR
is set) 也被禁用。
(3) 非阻塞模式的使用值得怀疑。
由于您希望 "每次 read() 函数调用只读取一行",因此阻塞模式是获得该结果的正确方法。
如果您坚持使用非阻塞模式,那么 read() 系统调用将始终 return “立即”并且可能 return 根本没有任何数据。