在Linux中的串口编程 [英] Serial port programming in Linux

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

问题描述

我想利用在董事会的 RS232 端口与PC进行通信。我知道我可以使用开发/ ttyS0来用于这一目的。

我可以打开和使用的写()功能将数据写入到PC。但问题是,我无法从开发/ ttyS0来读我每次使用读取功能,我得到资源暂时不可用。 u人能告诉我怎么解决这个问题呢?

下面是我的code:

 的#include<&stdio.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&fcntl.h GT;
#包括LT&;&termios.h GT;
#包括LT&;&unistd.h中GT;诠释的main()
{
    INT n = 0的,FD = 0,字节= 0;
    炭CH = 0;    炭缓冲液[10],* bufPtr;
    INT为nbytes = 0,尝试= 0,X = 0;    结构termios的期限;    FD =打开(为/ dev / ttyS0来,O_RDWR | O_NOCTTY | O_NDELAY);    如果(FD == -1)
    {
        PERROR(开放);
        返回;
    }
    其他
    {
        的fcntl(FD,F_SETFL,0);
        PERROR(端口);
    }    如果(N = tcgetattr(FD,与放大器术语)== -1)
    {
        PERROR(tcgetattr);
        返回;
    }    如果(N =之后,cfsetispeed(安培术语,B115200)== -1)
    {
        PERROR(之后,cfsetispeed);
        返回;
    }    如果(N = cfsetospeed来设置(安培术语,B115200)== -1)
    {
        PERROR(cfsetospeed来设置);
        返回;
    }    term.c_cflag | =(CLOCAL | CREAD);
    term.c_cflag&安培; =〜PARENB;
    term.c_cflag&安培; =〜CSTOPB;
    term.c_cflag&安培; =〜CSIZE;
    term.c_cflag | = CS8;
    term.c_lflag&安培; =〜(ICANON | ECHO | ECHOE | ISIG);
    term.c_iflag&安培; =〜(IXON | IXOFF | IXANY);
    term.c_cflag&安培; =〜CRTSCTS;
    term.c_oflag&安培; =〜OPOST;    如果(N = tcsetattr(FD,TCSANOW,&安培术语)== -1)
    {
        PERROR(tcsetattr);
        返回;
    }    写(FD,LINUX,5);
    PERROR(写);    使用fcntl(fd,F_SETFL,FNDELAY);
    PERROR(的fcntl);
    字节=读(FD,缓冲器,的sizeof(缓冲液));
    PERROR(读);
    的printf(字节数:%d和数据:%S \\ n,字节缓存);
}


解决方案

你是什么测试?你shortcutting 2脚和你的RS232 DB9连接器的3?

否则总是返回-1,如果没有数据被读取。

这是你的code应该使用 O_NDELAY 标志打开串口线做的。

要避免,如果没有要读取的数据读取,你可以使用选择
你的情况:

  timeval结构电视;
FD_SET RSET;
诠释retV;
INT超时= 5000; //5秒tv.tv_usec =(超时* 1000)%1000000;
tv.tv_sec =超时/ 1000;FD_ZERO(安培; RSET);
FD_SET(FD,&安培; RSET);
retV =选择(FD + 1,&安培; RSET,NULL,NULL,&安培;电视);如果(retV == 0)
{
   //超时的东西
}
否则如果(retV℃,)
{
    //错误的东西。阅读错误号,看看发生了什么
}
其他
{
   //读取数据
}

修改

删除的fcntl(FD,F_SETFL,FNDELAY);
如果你想有一个正常的阻塞读,未设置该标志。

在您的code您还假设将返回所有发送的字符,但事实并非如此。 将返回可用来读取字符。这意味着,如果你发送LINUX5次阅读可以请求读取发送的所有字符5

最后一件事

 的printf(字节数:%d和数据:%S \\ n,字节缓存);

因为缓存 >是不是一个 NULL 结尾的字符串。你可以解决它的循环上接收到的字符和%C格式打印出来,或 NULL 终止与您的缓冲区:

 如果(字节数大于0)
   缓冲区[字节] ='\\ 0';

 字符stringToSend [] =LINUX;
size_t型LEN = strlen的(stringToSend)+1;写(FD,LINUX,LEN);
PERROR(写);为size_t receivedBytes = 0;
字节= 0;
而(receivedBytes< LEN)
{
   字节=读(FD,&放大器;缓冲器[receivedBytes],sizeof的(缓冲器)-1);
   PERROR(读);   如果(字节大于0)
       receivedBytes + =字节;
}的printf(字节数:%d和数据:%S \\ n,receivedBytes,缓冲区);

I want to use RS232 port on the board to communicate with a PC. I understand that I can use "dev/ttyS0" for that purpose.

I can open and write data to PC by using write() function. But the problem is I can't read from "dev/ttyS0". Every time I use read function, I get "Resource temporarily unavailable". Can u guys tell me how to solve this problem?

Here is my code:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

int main()
{
    int n = 0, fd = 0, bytes = 0;
    char ch = 0;

    char buffer[10], *bufPtr;
    int nBytes = 0, tries = 0, x = 0;

    struct termios term;

    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);

    if (fd == -1)
    {
        perror("open");
        return;
    }
    else
    {
        fcntl(fd, F_SETFL, 0);
        perror("Port");
    }

    if (n = tcgetattr(fd, &term) == -1)
    {
        perror("tcgetattr");
        return;
    }

    if (n = cfsetispeed(&term, B115200) == -1)
    {
        perror("cfsetispeed");
        return;
    }

    if (n = cfsetospeed(&term, B115200) == -1)
    {
        perror("cfsetospeed");
        return;
    }

    term.c_cflag |= (CLOCAL | CREAD);
    term.c_cflag &= ~PARENB;
    term.c_cflag &= ~CSTOPB;
    term.c_cflag &= ~CSIZE;
    term.c_cflag |= CS8;
    term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    term.c_iflag &= ~(IXON | IXOFF | IXANY);
    term.c_cflag &= ~CRTSCTS;
    term.c_oflag &= ~OPOST; 

    if (n = tcsetattr(fd, TCSANOW, &term) == -1)
    {
        perror("tcsetattr");
        return;
    }

    write(fd,"LINUX",5);
    perror("write");

    fcntl(fd, F_SETFL, FNDELAY);    
    perror("fcntl");
    bytes = read(fd, buffer, sizeof(buffer));
    perror("read");
    printf("Bytes : %d and data: %s\n", bytes, buffer);
}

解决方案

What is your test? Are you shortcutting pin 2 and 3 of your RS232 DB9 connector?

Otherwise read will always return -1 if there are no data to be read.

This is what your code is supposed to do using O_NDELAY flag opening the serial line.

To avoid to read if there are no data to be read, you could use select In your case:

struct timeval tv;
fd_set rset;
int retV;
int timeout = 5000; // 5 seconds

tv.tv_usec = (timeout * 1000) % 1000000;
tv.tv_sec = timeout / 1000;

FD_ZERO ( &rset );
FD_SET (  fd, &rset );
retV = select ( fd+1, &rset, NULL, NULL, &tv );

if( retV == 0 )
{
   // timeout stuff
}
else if( retV < 0 )
{
    // Error stuff. Read errno to see what happened
}
else
{
   // read data
}

EDIT

Remove fcntl(fd, F_SETFL, FNDELAY); If you want a normal blocking read, unset that flag.

In your code you are also assuming that read will return all sent chars but is not true. read will return chars that are available to be read. This means that if you send "LINUX" a 5 times read could be requested to read all 5 chars sent.

Last thing

printf("Bytes : %d and data: %s\n", bytes, buffer);

is Undefined Behavior because of buffer is not a NULL terminated string. You could solve it looping on received chars and print it with %c format, or NULL terminating your buffer with:

if (bytes > 0)
   buffer[bytes] = '\0';

or

char stringToSend[] = "LINUX";
size_t len = strlen(stringToSend) +1 ;

write(fd,"LINUX", len);
perror("write");

size_t receivedBytes = 0;
bytes = 0;
while (receivedBytes<len)
{
   bytes = read(fd, &buffer[receivedBytes], sizeof(buffer)-1);
   perror("read");

   if (bytes > 0)
       receivedBytes += bytes;
}

printf("Bytes : %d and data: %s\n", receivedBytes, buffer);

这篇关于在Linux中的串口编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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