简体   繁体   中英

Serial port programming in Linux

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM