我正在尝试使用以下C代码从我的串口读取。我可以成功写入监听计算机(耶!)但读取错误(代码11 - 资源暂时不可用)。我也注意到我的消息/ dmesg日志没有任何关于故障的信息等。这很好。
//A bunch of INCLUDES exist here....the the code
int fd=0;
int status=0;
int running=1;
char buffer[100];
char message[7];
void main(){
fd = 1;
fd=open("/dev/ttyM0",O_RDWR | O_NOCTTY);
if(fd == -1)
{
perror("open_port: Unable to open /dev/ttys0");
}
else
{
while(running<20)
{
sprintf(message,"Test%d\r",running);
status=write(fd,message,6);
if(status<0)
{
printf("Error Writing. Status=%d\n %s\n",errno, strerror(errno));
}
status=read(fd,buffer,8); //This throws an error(11). My connected device is writing "Testing/r"
if(status<0)
{
printf("Error Reading. Status=%d \n%s\n",errno, strerror(errno));
//close(fd);
running=running+1;
}
else
{
printf("%s\n\r",buffer);
}
sleep(2);
}
close(fd);
}
} //END MAIN
这些是我的端口的串行设置。我试图以9600 8bit读取/写入,无奇偶校验,1个停止位。我认为我的设置是正确的。
sudo stty -a -F /dev/ttyM0
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
-imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
非常感谢任何帮助。谢谢!
答案 0 :(得分:2)
这里有缓冲区溢出:
sprintf(message,"Test%d\r",running);
因为message
被声明为:
char message[6];
message
如果要包含6个字符的字符串,则需要至少7个字符,因为需要'\0'
终止符。
也可能存在其他问题,但你应该解决这个问题,看看它是否有任何不同。
答案 1 :(得分:2)
您在O_NDELAY
电话中使用了open
选项。这使文件描述符非阻塞。这意味着如果您执行read
并且没有可用数据,则read
来电将返回EAGAIN
,这是您看到的错误。
目前,您可以从O_NDELAY
移除open
。将来,您可能应该再次进行非阻止,并使用select
或poll
来确定何时可以阅读。
答案 2 :(得分:1)
随着O_NDELAY的消失,程序就坐在那里等待输入
看起来 termios 是针对规范输入设置的(基于 stty 输出中的 icanon )。在规范(aka熟)模式下,从串口接收的字符在使用 read()提供给用户程序之前进行处理。
根据Linux手册页:
在规范模式中:
- 输入逐行可用。输入行可用 当键入其中一个行分隔符时(NL,EOL,EOL2;或EOF at。) 行的开头)。除了EOF的情况,行分隔符 包含在read(2)返回的缓冲区中。
您的 termios 也设置了 icrnl ,这意味着在输入时将回车转换为换行符(除非设置了 igncr ,不是因为它有一个前面的连字符)。 eol 和 eol2 都未定义(默认值)。
因此,对于您的设置,行尾定义为换行符或回车符(或行开头的cntl-D)。验证您的远程设备实际上是否正在发送CR或LF控制字符以终止该线路。您在代码中的注释表明它不是(即“/ r”不是回车符。)
要正确使用 read()返回的文本作为字符串,请将请求设置为小于分配的缓冲区大小(以确保附加空终止符的空间)。然后在返回良好后,使用返回的字节数作为索引来存储字符串终止符。
status = read(fd, buffer, sizeof(buffer) - 1);
if (status < 0) {
/* handle error condition */
} else {
buffer[status] = '\0';
printf("%s\n\r", buffer);
}