我正在尝试从串行端口读取数据,并从此处获取了示例代码:
http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html
代码示例是:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
/* baudrate settings are defined in <asm/termbits.h>, which is
included by <termios.h> */
#define BAUDRATE B9600
//B38400
/* change this definition for the correct port */
#define MODEMDEVICE "/dev/ttyACM0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
printf("starting program\n");
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
/*
Open modem device for reading and writing and not as controlling tty
because we don't want to get killed if linenoise sends CTRL-C.
*/
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
printf("fd=%d\n", fd);
tcgetattr(fd,&oldtio); /* save current serial port settings */
bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
/*
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
CRTSCTS : output hardware flow control (only used if the cable has
all necessary lines. See sect. 7 of Serial-HOWTO)
CS8 : 8n1 (8bit,no parity,1 stopbit)
CLOCAL : local connection, no modem contol
CREAD : enable receiving characters
*/
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
/*
IGNPAR : ignore bytes with parity errors
ICRNL : map CR to NL (otherwise a CR input on the other computer
will not terminate input)
otherwise make device raw (no other input processing)
*/
newtio.c_iflag = IGNPAR | ICRNL;
/*
Raw output.
*/
newtio.c_oflag = 0;
/*
ICANON : enable canonical input
disable all echo functionality, and don't send signals to calling program
*/
newtio.c_lflag = ICANON;
/*
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
*/
newtio.c_cc[VINTR] = 0; /* Ctrl-c */
newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */
newtio.c_cc[VERASE] = 0; /* del */
newtio.c_cc[VKILL] = 0; /* @ */
newtio.c_cc[VEOF] = 4; /* Ctrl-d */
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
newtio.c_cc[VSWTC] = 0; /* '\0' */
newtio.c_cc[VSTART] = 0; /* Ctrl-q */
newtio.c_cc[VSTOP] = 0; /* Ctrl-s */
newtio.c_cc[VSUSP] = 0; /* Ctrl-z */
newtio.c_cc[VEOL] = 0; /* '\0' */
newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */
newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */
newtio.c_cc[VWERASE] = 0; /* Ctrl-w */
newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */
newtio.c_cc[VEOL2] = 0; /* '\0' */
/*
now clean the modem line and activate the settings for the port
*/
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
printf("tcsetattr returned %d\n", res);
printf("just before while STOP loop\n");
/*
terminal settings done, now handle input
In this example, inputting a 'z' at the beginning of a line will
exit the program.
*/
while (STOP==FALSE) { /* loop until we have a terminating condition */
/* read blocks program execution until a line terminating character is
input, even if more than 255 chars are input. If the number
of characters read is smaller than the number of chars available,
subsequent reads will return the remaining chars. res will be set
to the actual number of characters actually read */
printf("just before read\n");
res = read(fd,buf,255);
printf("just after read\n");
buf[res]=0; /* set end of string, so we can printf */
printf(":%s:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
/* restore the old port settings */
tcsetattr(fd,TCSANOW,&oldtio);
}
然后我像这样编译并运行:
须藤./a.out
但是我得到的唯一输出是:
starting program
fd=3
tcsetattr returned 0
just before while STOP loop
just before read
我试过用手机响调制解调器,但是什么也没有。
如果我执行ls / dev / ttyA *,我会看到/ dev / ttyACM0
我需要以某种方式配置端口吗?
调制解调器是Conexant 93010语音调制解调器。绝对可以。我在VMWare VM中运行ubuntu有点复杂。但是我确实连接了VM,当我连接设备时,确实看到了ttyACM0。
更新
我在测试中发现我确实获得了输出,但是它非常延迟。例如,如果我打铃,我最终会显示RING。但是我必须不断地通过调制解调器响铃,切断线路,然后再次响铃。 15次响铃后,我看到输出。我将读取更改为一次只能读取5个字符。为什么要延迟?
如果我将read调用更改为一次读取10个字符,则其行为相同。我需要15到16声振铃才能看到屏幕上打印的任何数据(所有那些RING)。
我在Windows上运行串行代码,没有延迟。因此它不是硬件。
最佳答案
由于历史原因,串行驱动程序层中有许多设置会执行不同的预处理功能。看来您的问题出在这里:
newtio.c_lflag = ICANON;
...
newtio.c_cc[VEOF] = 4; /* Ctrl-d */
...
newtio.c_cc[VEOL] = 0; /* '\0' */
....
newtio.c_cc[VEOL2] = 0; /* '\0' */
根据termios的文档:
规范和非规范模式
c_lflag中ICANON佳能标志的设置确定是否
终端以规范模式(ICANON设置)或非规范-
ical模式(未设置ICANON)。默认情况下,设置ICANON。
在规范模式下:
逐行提供输入。输入线可用
当键入行定界符之一(NL,EOL,EOL2;或EOF为
行的开头)。除EOF以外,行定界符
包含在read(2)返回的缓冲区中。
因此,听起来这里发生的事情是内核缓冲区最终正在填满并将信息发送回给您,或者您正在获得控制字符之一(可能是虚假的)。
无论如何,尝试将
newio.c_lflag
设置为0;那应该清除规范的输入模式。 This related issue也可能有帮助。我通常会按以下说明清除所有termios设置,然后进行适当设置:
struct termios newio;
if( tcgetattr(fd, &newio) < 0 ){
/* Error checking */
}
newio.c_iflag |= IGNBRK;
newio.c_iflag &= ~BRKINT;
newio.c_iflag &= ~ICRNL;
newio.c_oflag = 0;
newio.c_lflag = 0;
newio.c_cc[VTIME] = 0;
newio.c_cc[VMIN] = 1;
if( tcsetattr( fd, TCSANOW, &newio ) < 0 ) {
/* Error checking */
}
如果您不想自己进行串行端口设置,则以上设置与我在C library和Java libraries中使用的设置相同。
关于c - 无法在Ubuntu上使用调制解调器读取任何数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55207112/