C

时间:2017-02-06 15:11:46

标签: c linux serial-port

我正在尝试编写一个简单的应用程序来读取Keithley 6485皮安表的当前值,该值通过Linux上的串行通信(RS232< - > USB)连接。

目前,可以通过对设备进行所有必要的初始化并发送" 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
 +----------------------------------+

但是,为了能够读取该值,我必须回应&#34; READ?&#34;每当我想知道值时,命令(或使用write()函数写入设备)。

如何以最优雅的方式将写入和读取放在同一个应用程序中(例如,不使用命名管道),因为当前read()函数等待来自设备的任何内容,在此期间我可以不发送&#34; READ?&#34;来自相同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 Serial Port Reading/Writing

并且在代码中找不到很大的差异 - 这是错误的端口设置的标志还是我错过了什么?

2 个答案:

答案 0 :(得分:1)

问题已解决!

显然,设备正在等待终端线终结器,char write_buffer[] = "READ?";

中没有

因此,当它收到这样的命令时,公共汽车将会“挂起”。为了让它再次工作,我们必须再次打开这个端口。

这也解释了为什么echo "READ?" > /dev/ttyUSB0命令有效 - 因为它会自动输出一个终止行终结符。

我附上下面的工作代码 - 谢谢大家的意见和善意的帮助!

  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

答案 1 :(得分:0)

在阅读之前使用select()或poll()来检查数据是否可用。如果没有可用的数据,则可以写入&#34; READ?&#34;命令。