Serial port programming in Linux

不羁岁月 提交于 2019-12-22 01:05:27

问题


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

回答1:


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);


来源:https://stackoverflow.com/questions/35032069/serial-port-programming-in-linux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!