2017-02-06 49 views
1

我正試圖編寫一個簡單的應用程序,通過串行通信(RS232 < - > USB)在Linux上連接一個Keithley 6485皮安表,讀取當前值。C中的串行通信

目前,可以通過執行所有需要的設備初始化併發送「READ?」來獲取這樣的值。它:echo "READ?" > /dev/ttyUSB0。然後,如果cat /dev/ttyUSB0一直在收聽,我會得到以下輸出:-2.250416E-14A,+8.320175E+03,+0.000000E+00,其中第一個數字是所需的值。

爲了能夠輸出I使用的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()函數等待來自設備的任何內容,並且在此期間無法發送「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 */ 

每當這個運行,我g et:

+----------------------------------+ 
|  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

,並不能找到代碼中很大的差異 - 那會是錯誤的端口設置的標誌還是我失去了一些東西?

+0

[Linux下C串行端口讀取/寫入]的可能的複製(http://stackoverflow.com/questions/18108932/linux-c-serial-port-reading-writing) – LPs

+1

你爲什麼不能打電話'write'在調用'read'來讀取答案之前發送查詢? –

+1

如果'read'在'read'之前被調用,該值不能被'read'訪問 - 我的猜測是它實時地逐字節地讀取它,而不是從緩衝區讀取 – vastas

回答

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 
+0

感謝它幫助 – achoora

0

在讀取之前使用select()或poll()來檢查數據是否可用。如果沒有數據可用,則可以寫入「READ?」命令。