【发布时间】:2021-11-17 02:02:07
【问题描述】:
总结:
我目前正在使用 termios 在嵌入式 Linux 上开发一个程序。如果我不启用偶校验,我的程序可以正常工作。当我将 PARENB 设置为活动且 PARODD 为非活动时,我开始遇到问题。我的程序设计为 115200 波特的 8E1。
发生的情况是,当我第一次在启用偶校验的全新启动时运行该程序时,它会发送一条消息。发送的消息确实发送,但它不发送奇偶校验位。我第二次运行该程序时,它在 tcsetattr 函数处失败,并带有 errno == EINVAL。
我在树莓派上运行这个程序进行调试,然后将程序移植到yocto环境中。
当前环境:
树莓派:4B Debian 版本:10.10 GCC:(Raspbian 8.3.0-6+rpi1)8.3.0。
我的问题:
有没有人知道丢失了什么?我自己尝试过这样做,并尝试了我在 GitHub 上找到的 2 个人的在线示例。他们都有这个问题。
我正在运行的代码是:
// C library headers
#include <stdio.h>
#include <string.h>
// Linux headers
#include <errno.h> // Error integer and strerror() function
#include <fcntl.h> // Contains file controls like O_RDWR
#include <stdlib.h>
#include <sys/types.h>
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()
#define SERIAL_DEVICE "/dev/ttyS0"
int main() {
struct termios serial_port_settings;
int fd;
int retval;
char buf[] = "hello world \n bye\n";
char ch;
int i;
//SERAIL_DEVICE is "/dev/ttyS0"
fd = open(SERIAL_DEVICE, O_RDWR);
if (fd < 0) {
perror("Failed to open SERIAL_DEVICE");
exit(1);
}
retval = tcgetattr(fd, &serial_port_settings);
if (retval < 0) {
perror("Failed to get termios structure");
exit(2);
}
//setting baud rate to B115200
retval = cfsetospeed(&serial_port_settings, B115200);
if (retval < 0) {
perror("Failed to set 115200 output baud rate");
exit(3);
}
retval = cfsetispeed(&serial_port_settings, B115200);
if (retval < 0) {
perror("Failed to set 115200 input baud rate");
exit(4);
}
//parity and bytes, grabbed from documentation
serial_port_settings.c_cflag |= PARENB; //enable parity
serial_port_settings.c_cflag &= ~PARODD; //disable odd parity, therefore-> even parity
serial_port_settings.c_cflag &= ~CSTOPB; //disable 2 stop bits, therefore-> 1 stop bit
serial_port_settings.c_cflag &= ~CSIZE; //remove size
serial_port_settings.c_cflag |= CS8; //8 data bits
serial_port_settings.c_cflag |= CLOCAL | CREAD; //ignore modem control lines, enable reciever
serial_port_settings.c_lflag |= ICANON; // enable canonical mode
retval = tcsetattr(fd, TCSANOW, &serial_port_settings);
/*************** ERROR HAPPENS HERE ********************/
/* errno is set to EINVAL here */
if (retval < 0) {
perror("Failed to set serial attributes");
exit(5);
}
printf("Successfully set the baud rate\n");
retval = write(fd, buf, 18);
if (retval < 0) {
perror("write on SERIAL_DEVICE failed");
exit(6);
}
retval = tcdrain(fd);
if (retval < 0) {
perror("write on SERIAL_DEVICE failed");
exit(6);
}
close(fd);
return 0;
}
【问题讨论】:
-
只看手册页就知道
ICANON是c_cflag而不是c_lflag -
@jiveturkey 很好。我在第二次尝试中确实解决了这个问题,但忘记在这个上修复它。我刚刚用那个编辑再次尝试了我的程序。问题仍然存在。我已经编辑了我的问题来解决这个问题。
-
ICANON 在 c_lflag 成员中。你本来是对的,现在是错的。在盲目跟随 cmets 之前,请自己阅读手册页。 FWIW 我添加了必要的#include 语句,编译了您的代码,并且没有遇到错误。
-
建议您在帖子中添加此嵌入式 Linux 板和工具链的详细信息。重新测试了修改后的版本,同样成功执行。这是在 x86 笔记本电脑上。我确实有各种各样的 SBC 要测试,但没有 RPi 或 Broadcom SoC。
-
Raspberry pi: 4B至少在 RPI3 上有两个 UART 驱动程序,一个完整的用于蓝牙,另一个是一个非常有限的迷你 UART 驱动程序。很可能您正在使用那个迷你 UART,它不支持任何模式。我明白了,rpi 文档发生了变化,记录在这里:raspberrypi.org/documentation/computers/…