Search code examples
linuxarduinousbserialtermios

my linux C program cannot receive data from Arduino through USB Serial


My Linux C application cannot receive bytes from Arduino

Hi all, I intend to use Arduino Mega 2560 as a programmer for AT89S52 (a family of 8051 microprocessor). The Arduino board connects to PC via USB Serial cable.

At first I need to write a program in my Ubuntu to communicate with Arduino board. My program can open connection and write bytes to Arduino properly (I tested by turning led on/off), but the problem is that the Linux program cannot receive data from Arduino. I already searched through many tutorials and forums but still cannot resolve the problem, so I post question here and hope that someone can help me.

  • Below is my functon used to open connection to device

    AT89S_EID    usbserial_open ( char* dev_name,
                                  UsbSerialDevice* dev_ptr,
                                  int baudrate,
                                  int config )  {
    speed_t io_baudrate = B9600;
    
    if (dev_name == NULL || dev_ptr == NULL)
    {
        return AT89S_EID_ARG_NULL;
    }
    
    if (baudrate != US_BAUDRATE_9600
        && baudrate != US_BAUDRATE_19200
        && baudrate != US_BAUDRATE_115200)
    {
        return AT89S_EID_SERIAL_BAUDRATE_INVALID;
    }
    if (config != US_CONFIG_8N1
        && config != US_CONFIG_7E1
        && config != US_CONFIG_7O1)
    {
        return AT89S_EID_SERIAL_CONFIG_INVALID;
    }
    
    // store device name
    strcpy(dev_ptr->name, dev_name);
    
    // open device
    dev_ptr->fd = open (dev_ptr->name,
                        O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
    if (dev_ptr->fd < 0)
    {
        return AT89S_EID_SERIAL_OPEN;
    }
    
    // get current termios settings
    if (tcgetattr(dev_ptr->fd, &dev_ptr->tios) < 0)
    {
        return AT89S_EID_SERIAL_GET_ATTR;
    }
    
    // set input/output baudrdate
    if (baudrate == US_BAUDRATE_9600)
        io_baudrate = B9600;
    else if (baudrate == US_BAUDRATE_19200)
        io_baudrate = B19200;
    else if (baudrate == US_BAUDRATE_115200)
        io_baudrate = B115200;
    
    if (cfsetispeed(&dev_ptr->tios, io_baudrate) != 0
        || cfsetospeed(&dev_ptr->tios, io_baudrate) != 0)
    {
        return AT89S_EID_SERIAL_SET_IOSPEED;
    }
    
    // enable receiver, ignore status line
    dev_ptr->tios.c_cflag |= (CREAD | CLOCAL);
    // set config
    if (config == US_CONFIG_8N1)
    {
        dev_ptr->tios.c_cflag &= ~PARENB;
        dev_ptr->tios.c_cflag &= ~CSTOPB;
        dev_ptr->tios.c_cflag &= ~CSIZE;
        dev_ptr->tios.c_cflag |= CS8;
    }
    else if (config == US_CONFIG_7E1)
    {
        dev_ptr->tios.c_cflag |= PARENB;
        dev_ptr->tios.c_cflag &= ~PARODD;
        dev_ptr->tios.c_cflag &= ~CSTOPB;
        dev_ptr->tios.c_cflag &= ~CSIZE;
        dev_ptr->tios.c_cflag |= CS7;
    }
    else if (config == US_CONFIG_7O1)
    {
        dev_ptr->tios.c_cflag |= PARENB;
        dev_ptr->tios.c_cflag |= PARODD;
        dev_ptr->tios.c_cflag &= ~CSTOPB;
        dev_ptr->tios.c_cflag &= ~CSIZE;
        dev_ptr->tios.c_cflag |= CS7;
    }
    
    // no HW flow control
    dev_ptr->tios.c_cflag &= ~CRTSCTS;
    
    // no input processing (raw input)
    dev_ptr->tios.c_iflag &= ~(IXON | IXOFF | IXANY);
    // other input settings
    dev_ptr->tios.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    // no output processing (raw output)
    dev_ptr->tios.c_oflag &= ~OPOST;
    
    // control character settings
    dev_ptr->tios.c_cc[VMIN]  = 1; // wait for 1 minimum chacacter received
    dev_ptr->tios.c_cc[VTIME] = 0; // no timeout when waiting for charater
    
    // commit new settings
    if (tcsetattr(dev_ptr->fd, TCSANOW, &dev_ptr->tios) < 0)
    {
        return AT89S_EID_SERIAL_SET_ATTR;
    }
    
    // wait for device reset & sync up
    usleep(1500 * 1000);
    return AT89S_EID_OK;
    } /* usbserial_open */
    
  • And this is the receiving function:

    AT89S_EID    usbserial_recv ( UsbSerialDevice* dev_ptr,
                                  unsigned char* data_ptr,
                                  int data_len ) {
    int read_byte = 0;
    char b[1];
    
    if (dev_ptr == NULL
        || data_ptr == NULL)
    {
        return AT89S_EID_ARG_NULL;
    }
    
    // block reading
    fcntl(dev_ptr->fd, F_SETFL, 0);
    
    // start receiving data
    while (read_byte < data_len)
    {
        if (read(dev_ptr->fd, b, 1) > 0)
        {
            data_ptr[read_byte++] = *b;
        }
        else
        {
            if (errno == EAGAIN)
                continue;
            else if (errno == ETIMEDOUT)
                break;
            else
                return AT89S_EID_SERIAL_RECV;
        }
    }
    
    return AT89S_EID_OK;
    } /* usbserial_recv */
    

So sorry for posting a long code :)

I already searched through many tutorials and forums but still cannot resolve the problem. I believe that the Arduino code is working fine because I used some other tools to test it (e.g.: minicom)


Solution

  • I resolved my problem. Just add flush function when open the connection to device, everything can be working fine.

    tcflush(fd, TCIOFLUSH);