Linux的串行读抛出错误 [英] Linux Serial Read throws Error

查看:153
本文介绍了Linux的串行读抛出错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从我的串口读取使用下面的C code。我可以成功地写入监听计算机(耶!),但读抛出错误(code 11 - 资源暂时不可用)。我也注意到我的邮件/ dmesg的日志没有关于故障的任何信息,等等。所以这是很好的。

  // A的一堆INCLUDES存在这里....在了codeINT FD = 0;
INT状态= 0;
诠释运行= 1;
炭缓冲器[100];
CHAR消息[7];无效的主要(){
    FD = 1;    FD =打开(/开发/ ttyM0,O_RDWR | O_NOCTTY);    如果(FD == -1)
    {
        PERROR(open_port:无法打开/ dev / ttyS0来);
    }
    其他
    {
        而(运行< 20)
        {
            sprintf的(消息,测试%d个\\ r,即运行);
            状态=写(FD,消息,6);            如果(状态℃下)
            {
                的printf(写入状态=%d个\\ n%S \\ n,错误号,字符串错误(错误));
            }
            状态=读(FD,缓冲液,8); //这引发错误(11)。我的连接设备正在写测试/ R            如果(状态℃下)
            {
                的printf(错误读取状态=%d个\\ n%S \\ n,错误号,字符串错误(错误));
                //关闭(FD);
                运行=跑+ 1;
            }
            其他
            {
                的printf(%S \\ n \\ r,即缓冲);
            }
            睡眠(2);
        }
        关闭(FD);
    }} // END MAIN

这是我为我的串口设置。我试图在9600 8位,无奇偶校验,1个停止位为读/写。我觉得我的设置是正确的。

 须藤的stty -a -f /开发/ ttyM0
速度9600波特;行0;列0;行= 0;
INTR = ^ C;退出= ^ \\;擦除= ^?;杀= ^ U; EOF = ​​^ D; EOL =<民主基金取代; EOL2 =<民主基金取代;
动开关= LT;民主基金取代;开始= ^ Q;停止= ^ S;停赛= ^ Z; rprnt = ^ R; WERASE = ^ W; LNEXT = ^ V;
冲水= ^ O;分= 1;时间= 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回声ECHOE ECHOK -echonl -noflsh -xcase -tostop -echoprt ECHOCTL ECHOKE

任何帮助将非常AP preciated。谢谢!


解决方案

  

通过O_NDELAY了该方案只是坐在那里等待输入


看起来像的的termios 的是标准输入设置(基于 ICANON 的stty 输出)。在规范(又名熟)模式下,从串口接收字符使用被提供给用户程序之前处理的阅读()

每Linux手册页:


  

在标准模式:


  
  

      
  • 输入由线提供行。输入线可用
      当行分隔符之一类型(NL,EOL,EOL2;或在EOF
      行的开始)。除EOF,该行分隔符的情况下,
      被包含在由读出的(2)。
  • 返回的缓冲
      

您的的termios 的也有 ICRNL 集,这意味着一个回车翻译为新行输入(除非 IGNCR 设置,这不是因为它有一个preceding连字符)。双方的 EOL EOL2 是不确定的(这是默认值)。

所以对你的设置,最终的线被定义为一个新行或回车(或CNTL-D在该行的开始)。验证您的远程设备实际发送CR或LF控制字符来终止该行。您在code注释表明它不是(即/ R是不是回车)。


要正确使用由阅读()作为一个字符串返回的文本,设置比分配的缓冲区大小又少了一个请求(保证房间追加空终止)。然后,一个好的回报后,使用返回的字节数为存储字符串结束的索引。

 状态=读(FD,缓冲区,缓冲区尺寸 -  1);
        如果(状态℃,){
            / *处理错误状态* /
        }其他{
            缓冲[状态] ='\\ 0';
            的printf(%S \\ n \\ r,即缓冲);
        }

I'm attempting to read from my serial port using the following C code. I can successfully write to a listening computer (yay!) but the read throws Error (Code 11 - Resource temporarily unavailable). I have also noticed my messages/dmesg logs don't have any information regarding faults,etc. So that's good.

//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

These are my serial settings for my port. I'm attempting to read/write at 9600 8bit, No parity, 1 stop bit. I think my settings are correct.

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

Any help would be very much appreciated. Thank you!

解决方案

With O_NDELAY gone the program just sits there waiting for input

Looks like termios is setup for canonical input (based on the icanon in the stty output). In canonical (aka cooked) mode, the characters received from the serial port are processed before being made available to the user program using read().

Per the Linux man page:

In canonical mode:

  • Input is made available line by line. An input line is available when one of the line delimiters is typed (NL, EOL, EOL2; or EOF at the start of line). Except in the case of EOF, the line delimiter is included in the buffer returned by read(2).

Your termios also has icrnl set, which means that a carriage return is translated to newline on input (unless igncr is set, which is not since it has a preceding hyphen). Both eol and eol2 are undefined (which are the default values).

So for your setup, an end-of-line is defined as a newline or a carriage return (or cntl-D at the start of the line). Verify that your remote device is actually sending a CR or LF control character to terminate the line. Your comment in the code indicates that it is not (i.e. "/r" is not a carriage return).


To properly use the text returned by read() as a string, set the request for one less than the allocated buffer size (to ensure room for appending a null terminator). Then after a good return, use the returned byte count as the index to store the string terminator.

        status = read(fd, buffer, sizeof(buffer) - 1);  
        if (status < 0) {
            /* handle error condition */
        } else {
            buffer[status] = '\0';
            printf("%s\n\r", buffer);
        }

这篇关于Linux的串行读抛出错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆