Linux Serial Read抛出错误

时间:2015-09-11 15:04:14

标签: c linux serial-port

我正在尝试使用以下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

非常感谢任何帮助。谢谢!

3 个答案:

答案 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。将来,您可能应该再次进行非阻止,并使用selectpoll来确定何时可以阅读。

答案 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);
        }