ฉันกำลังพยายามเขียนแอปพลิเคชันง่ายๆ เพื่ออ่านค่าปัจจุบันจาก Keithley 6485 picoammeter ที่เชื่อมต่อผ่านการสื่อสารแบบอนุกรม (RS232<->USB) บน linux

ในปัจจุบัน ค่าดังกล่าวสามารถเรียกค้นได้โดยทำการเริ่มต้นอุปกรณ์ที่จำเป็นทั้งหมดแล้วส่ง "READ?" ไปที่มัน: echo "READ?" > /dev/ttyUSB0. ถ้าcat /dev/ttyUSB0ได้ฟังแล้วจะได้ผลลัพธ์ดังนี้-2.250416E-14A,+8.320175E+03,+0.000000E+00, ซึ่งตัวเลขแรกเป็นค่าที่ต้องการ

เพื่อให้สามารถส่งออกค่าได้ ฉันใช้รหัสต่อไปนี้โดยใช้ไลบรารี termios:

    /*====================================================================================================*/
    /* Serial Port Programming in C (Serial Port Read)                                                    */
/* Non Cannonical mode                                                                                */
/*----------------------------------------------------------------------------------------------------*/
    /* Program reads a string from the serial port at 9600 bps 8N1 format                                 */
/* Baudrate - 9600                                                                                    */
/* Stop bits -1                                                                                       */
/* No Parity                                                                                          */
    /*----------------------------------------------------------------------------------------------------*/
/* Compiler/IDE  : gcc 4.6.3                                                                          */
/* Library       :                                                                                    */
/* Commands      : gcc -o serialport_read serialport_read.c                                           */
/* OS            : Linux(x86) (Linux Mint 13 Maya)(Linux Kernel 3.x.x)                                */                              
/* Programmer    : Rahul.S                                                                            */
/* Date          : 21-December-2014                                                                   */
/*====================================================================================================*/

/*====================================================================================================*/
/* www.xanthium.in                                            */
/* Copyright (C) 2014 Rahul.S                                                                         */
/*====================================================================================================*/

/*====================================================================================================*/
/* Running the executable                                                                             */
/* ---------------------------------------------------------------------------------------------------*/ 
/* 1) Compile the  serialport_read.c  file using gcc on the terminal (without quotes)                 */
    /*                                                                                                    */
/*  " gcc -o serialport_read serialport_read.c "                                                  */
/*                                                                                                    */
    /* 2) Linux will not allow you to access the serial port from user space,you have to be root.So use   */
    /*    "sudo" command to execute the compiled binary as super user.                                    */
    /*                                                                                                    */
    /*       "sudo ./serialport_read"                                                                     */
/*                                                                                                    */
/*====================================================================================================*/

/*====================================================================================================*/
/* Sellecting the Serial port Number on Linux                                                         */
/* ---------------------------------------------------------------------------------------------------*/ 
/* /dev/ttyUSBx - when using USB to Serial Converter, where x can be 0,1,2...etc                      */
/* /dev/ttySx   - for PC hardware based Serial ports, where x can be 0,1,2...etc                      */
    /*====================================================================================================*/

/*-------------------------------------------------------------*/
    /* termios structure -  /usr/include/asm-generic/termbits.h    */ 
/* use "man termios" to get more info about  termios structure */
/*-------------------------------------------------------------*/

    #include <stdio.h>
    #include <fcntl.h>   /* File Control Definitions           */
    #include <termios.h> /* POSIX Terminal Control Definitions */
    #include <unistd.h>  /* UNIX Standard Definitions      */ 
    #include <errno.h>   /* ERROR Number Definitions           */

void main(void)
    {
        int fd;/*File Descriptor*/

    printf("\n +----------------------------------+");
    printf("\n |        Serial Port Read          |");
    printf("\n +----------------------------------+");

    /*------------------------------- Opening the Serial Port -------------------------------*/

    /* Change /dev/ttyUSB0 to the one corresponding to your system */

        fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY);    /* ttyUSB0 is the FT232 based USB2SERIAL Converter   */
    //  fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY); /* ttyUSB0 is the FT232 based USB2SERIAL Converter   */
                            /* O_RDWR   - Read/Write access to serial port       */
                            /* O_NOCTTY - No terminal will control the process   */
                            /* Open in blocking mode,read will wait              */



        if(fd == -1)                        /* Error Checking */
               printf("\n  Error! in Opening ttyUSB0  ");
        else
               printf("\n  ttyUSB0 Opened Successfully ");


    /*---------- Setting the Attributes of the serial port using termios structure --------- */

    struct termios SerialPortSettings;  /* Create the structure                          */

    tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */

    /* Setting the Baud rate */
    cfsetispeed(&SerialPortSettings,B19200); /* Set Read  Speed as 19200                       */
    cfsetospeed(&SerialPortSettings,B19200); /* Set Write Speed as 19200                       */

    /* 8N1 Mode */
    SerialPortSettings.c_cflag &= ~PARENB;   /* Disables the Parity Enable bit(PARENB),So No Parity   */
    SerialPortSettings.c_cflag &= ~CSTOPB;   /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
    SerialPortSettings.c_cflag &= ~CSIZE;    /* Clears the mask for setting the data size             */
    SerialPortSettings.c_cflag |=  CS8;      /* Set the data bits = 8                                 */

    SerialPortSettings.c_cflag &= ~CRTSCTS;       /* No Hardware flow Control                         */
    SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines       */ 


    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);          /* Disable XON/XOFF flow control both i/p and o/p */
    SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);  /* Non Cannonical mode                            */

    SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/

    /* Setting Time outs */
    SerialPortSettings.c_cc[VMIN] = 13; /* Read at least 10 characters */
    SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly   */


    if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
        printf("\n  ERROR ! in Setting attributes");
    else
                printf("\n  BaudRate = 19200 \n  StopBits = 1 \n  Parity   = none");

        /*------------------------------- Read data from serial port -----------------------------*/

    char read_buffer[32];   /* Buffer to store the data received              */
    int  bytes_read = 0;    /* Number of bytes read by the read() system call */
    int i = 0;

    tcflush(fd, TCIFLUSH);   /* Discards old data in the rx buffer            */

    bytes_read = read(fd,&read_buffer,32); /* Read the data                   */

    printf("\n\n  Bytes Rxed -%d", bytes_read); /* Print the number of bytes read */
    printf("\n\n  ");
    for(i=0;i<13;i++)    /*printing only the needed bytes*/
        printf("%c",read_buffer[i]);

    printf("\n +----------------------------------+\n\n\n");

    close(fd); /* Close the serial port */

    }

ผลลัพธ์ใด:

 +----------------------------------+
 |        Serial Port Read          |
 +----------------------------------+
  ttyUSB0 Opened Successfully 
  BaudRate = 19200 
  StopBits = 1 
  Parity   = none

  Bytes Rxed -13

  -2.864104E-14
 +----------------------------------+

อย่างไรก็ตาม เพื่อให้สามารถอ่านค่าได้ ฉันต้องสะท้อน "READ?" คำสั่ง (หรือเขียนไปยังอุปกรณ์โดยใช้ฟังก์ชัน write()) ทุกครั้งที่ต้องการทราบค่า

ฉันจะใส่ทั้งการเขียนและการอ่านลงในแอปพลิเคชันเดียวกันในลักษณะที่หรูหราที่สุดได้อย่างไร (เช่น โดยไม่ต้องสร้างไพพ์ที่มีชื่อ) เนื่องจากขณะนี้ฟังก์ชัน read() จะรอให้สิ่งใดมาจากอุปกรณ์และในช่วงเวลานั้น ฉันไม่สามารถส่ง "อ่าน?" คำสั่งจากรหัส C เดียวกัน?


แก้ไข: เห็นได้ชัดว่าขั้นตอนการเขียนของฉันทำงานไม่ถูกต้อง:

การตั้งค่าพอร์ต:

    struct termios SerialPortSettings;  /* Create the structure                          */

    tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */

    cfsetispeed(&SerialPortSettings,(speed_t)B19200); /* Set Read  Speed as 19200                       */
    cfsetospeed(&SerialPortSettings,(speed_t)B19200); /* Set Write Speed as 19200                       */

    SerialPortSettings.c_cflag &= ~PARENB;   /* Disables the Parity Enable bit(PARENB),So No Parity   */
    SerialPortSettings.c_cflag &= ~CSTOPB;   /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
    SerialPortSettings.c_cflag &= ~CSIZE;    /* Clears the mask for setting the data size             */
    SerialPortSettings.c_cflag |=  CS8;      /* Set the data bits = 8                                 */

    SerialPortSettings.c_cflag = ~CRTSCTS;       /* No Hardware flow Control                         */
    SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines       */ 


cfmakeraw(&SerialPortSettings);

tcflush(fd,TCIFLUSH);

    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);          // Disable XON/XOFF flow control both i/p and o/p
    SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);  // Non Cannonical mode                           
    SerialPortSettings.c_oflag &= ~OPOST;//No Output Processing

การเขียน:

    char write_buffer[] = "READ?";  /* Buffer containing characters to write into port       */ 
    int  bytes_written  = 0;    /* Value for storing the number of bytes written to the port */ 

    bytes_written = write(fd,&write_buffer,sizeof(write_buffer) -1);
printf("%s written to ttyUSB0 \n",write_buffer);
    printf("%d Bytes written to ttyUSB0 \n", bytes_written);
    printf("+----------------------------------+\n\n");

    close(fd);/* Close the Serial port */

เมื่อใดก็ตามที่สิ่งนี้ทำงาน ฉันจะได้รับ:

+----------------------------------+ 
|        Serial Port Write         | 
+----------------------------------+ 
ttyUSB0 Opened Successfully 
Attributes set 
READ? written to ttyUSB0 
5 Bytes written to ttyUSB0 
+----------------------------------+

แต่cat /dev/ttyUSB0ดูเหมือนจะไม่เห็นอะไรออกมาจากอุปกรณ์ ฉันได้ตรวจสอบคำถามที่คล้ายกันที่:

การอ่าน/เขียนพอร์ตอนุกรม Linux C

และไม่พบความแตกต่างอย่างมากในโค้ด - นั่นเป็นสัญญาณของการตั้งค่าพอร์ตที่ไม่ถูกต้องหรือฉันทำพลาดอะไรไป

ตอบ

ปัญหาได้รับการแก้ไขแล้ว!

เห็นได้ชัดว่าอุปกรณ์กำลังรอ end-line terminator ซึ่งไม่พร้อมใช้งานใน char write_buffer[] = "READ?";

ดังนั้นเมื่อได้รับคำสั่งดังกล่าว รถบัสจะ "แฮงค์" และเพื่อให้ทำงานได้อีกครั้ง จะต้องเปิดพอร์ตอีกครั้ง

สิ่งนี้ยังอธิบายด้วยว่าเหตุใดecho "READ?" > /dev/ttyUSB0คำสั่งจึงทำงาน - เนื่องจากมันจะส่งออก end-line terminator โดยอัตโนมัติ

ฉันแนบรหัสการทำงานด้านล่าง - ขอบคุณทุกคนสำหรับความคิดเห็นและความช่วยเหลือของคุณ!

  int fd;           //device file id
//------------------------------- Opening the Serial Port -------------------------------
    fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY);    // ttyUSB0 is the FT232 based USB2SERIAL Converter 
    if(fd == -1)                        // Error Checking 
    printf("Error while opening the device\n");
//---------- Setting the Attributes of the serial port using termios structure ---------
    struct termios SerialPortSettings;  // Create the structure                          
    tcgetattr(fd, &SerialPortSettings); // Get the current attributes of the Serial port
// Setting the Baud rate
  cfsetispeed(&SerialPortSettings,B19200); // Set Read  Speed as 19200                       
    cfsetospeed(&SerialPortSettings,B19200); // Set Write Speed as 19200                       

    SerialPortSettings.c_cflag &= ~PARENB;   // Disables the Parity Enable bit(PARENB),So No Parity   
    SerialPortSettings.c_cflag &= ~CSTOPB;   // CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit 
    SerialPortSettings.c_cflag &= ~CSIZE;    // Clears the mask for setting the data size             
    SerialPortSettings.c_cflag |=  CS8;      // Set the data bits = 8                                 
    SerialPortSettings.c_cflag &= ~CRTSCTS;       // No Hardware flow Control                         
    SerialPortSettings.c_cflag |= CREAD | CLOCAL; // Enable receiver,Ignore Modem Control lines        
    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);  // Disable XON/XOFF flow control both i/p and o/p 
    SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);  // Non Cannonical mode 
    SerialPortSettings.c_oflag &= ~OPOST;//No Output Processing
// Setting Time outs 
    SerialPortSettings.c_cc[VMIN] = 13; // Read at least 10 characters 
    SerialPortSettings.c_cc[VTIME] = 0; // Wait indefinetly  

    if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) // Set the attributes to the termios structure
    printf("Error while setting attributes \n");
    //------------------------------- Read data from serial port -----------------------------

    char read_buffer[32];   // Buffer to store the data received              
    int  bytes_read = 0;    // Number of bytes read by the read() system call 
  int bytes_written = 0;  // Number of bytes written
    int i = 0;

    tcflush(fd, TCIFLUSH);   // Discards old data in the rx buffer            
//Device intialization

  char write_buffer[]="READ? \n ";
  bytes_written=write(fd,&write_buffer,sizeof(write_buffer));


  bytes_read = read(fd,&read_buffer,32); // Read the data                   

    for(i=0;i<13;i++)    //printing only the needed characters
    printf("%c",read_buffer[i]);
    close(fd); // Close the serial port

ใช้ select() หรือ poll() ก่อนอ่านเพื่อตรวจสอบว่ามีข้อมูลหรือไม่ หากไม่มีข้อมูล คุณสามารถเขียน "READ?" สั่งการ.