system("stty erase ^H);system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter into non-canonical (raw) mode
这将是不充分的代码(以及每个POSIX约定的不良编码实践)将串行端口置于原始或非规范模式。
C和Linux中最简单的方法是使用cfmakeraw()GNU libc和uClibc库中提供的函数。使用手册页获取有关修改的termios结构成员的详细信息cfmakeraw()。
请注意,对于10位的总字符帧(假设一个停止位),cfmakeraw()将在原始模式下设置串行端口,数据长度为8位且无奇偶校验。
首选方法是保留termios结构的副本(用于程序退出时的恢复)并仅修改所需的标志位(而不是编写完整的结构成员)。
修订
适用于我的ARM SoC的代码是:#include #include #include #include #include #include #include #include #include #include #include #define SERIALPORT_IS_CONSOLEmain(){
struct termios tty;
struct termios savetty;
speed_t spd;
unsigned int sfd;
unsigned char buf[80];
int reqlen = 79;
int rc;
int rdlen;
int pau = 0;#ifdef SERIALPORT_IS_CONSOLE
sfd = STDIN_FILENO;#else
sfd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);#endif
if (sfd
syslog(LOG_DEBUG, "failed to open: %d, %s", sfd, strerror(errno));
exit (-1);
}
syslog(LOG_DEBUG, "opened sfd=%d for reading", sfd);
rc = tcgetattr(sfd, &tty);
if (rc
syslog(LOG_DEBUG, "failed to get attr: %d, %s", rc, strerror(errno));
exit (-2);
}
savetty = tty; /* preserve original settings for restoration */
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
rc = tcsetattr(sfd, TCSANOW, &tty);
if (rc
syslog(LOG_DEBUG, "failed to set attr: %d, %s", rc, strerror(errno));
exit (-3);
}
do {
unsigned char *p = buf;
rdlen = read(sfd, buf, reqlen);
if (rdlen > 0) {
if (*p == '\r')
pau = 1;
syslog(LOG_DEBUG, "read: %d, 0x%x 0x%x 0x%x", \
rdlen, *p, *(p + 1), *(p + 2));
} else {
syslog(LOG_DEBUG, "failed to read: %d, %s", rdlen, strerror(errno));
}
} while (!pau);
tcsetattr(sfd, TCSANOW, &savetty);
close(sfd);
exit (0);}
编译的程序在目标板上加载和执行。
从串行通信链路的主机端,seq.bin发送包含以下内容的文件:$ od -t x1 seq.bin0000000 aa 02 fe0000003
然后在主机(运行minicom终端仿真器程序)上键入“ABC” ,然后回车。程序终止于目标,然后检查syslog:# tail /var/log/messages Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3 FS on nvsram, internal journal Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3-fs: mounted filesystem with or.Sep xx xx:xx:42 atmel_soc user.info kernel: kjournald starting. Commit intervasSep xx xx:xx:18 atmel_soc auth.info login[431]: root login on 'ttyS0' Sep xx xx:xx:04 atmel_soc user.debug syslog: opened sfd=0 for reading Sep xx xx:xx:14 atmel_soc user.debug syslog: read: 3, 0xaa 0x2 0xfe Sep xx xx:xx:50 atmel_soc user.debug syslog: read: 1, 0x41 0x2 0xfe Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x42 0x2 0xfe Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x43 0x2 0xfe Sep xx xx:xx:52 atmel_soc user.debug syslog: read: 1, 0xd 0x2 0xfe #
二进制数据已完整收到。
请注意,由于这是原始模式并且输入的类型字符相对较慢,因此read()返回“部分”数据和用户程序将负责将数据缓冲/组装成完整的“消息”。如果消息具有固定长度,则可以将c_cc[VMIN]成员设置为消息长度。但是,当帧同步丢失时,请注意消息帧的问题和复杂性!