首页 文章

在Linux上读取和写入C语言中的串行端口

提问于
浏览
34

我正在尝试 send/receive data over an USB Port using FTDI ,所以我需要使用C / C处理串行通信 . 我正在研究 Linux (Ubuntu) .

基本上,我连接到正在侦听传入命令的设备 . 我需要发送这些命令并读取设备的响应 . 命令和响应都是 ASCII characters .

使用GtkTerm一切正常,但是当我切换到C编程时,我遇到了问题 .

这是我的代码:

#include <stdio.h>      // standard input / output functions
#include <stdlib.h>
#include <string.h>     // string function definitions
#include <unistd.h>     // UNIX standard function definitions
#include <fcntl.h>      // File control definitions
#include <errno.h>      // Error number definitions
#include <termios.h>    // POSIX terminal control definitions

/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY );

/* Error Handling */
if ( USB < 0 )
{
cout << "Error " << errno << " opening " << "/dev/ttyUSB0" << ": " << strerror (errno) << endl;
}

/* *** Configure Port *** */
struct termios tty;
memset (&tty, 0, sizeof tty);

/* Error Handling */
if ( tcgetattr ( USB, &tty ) != 0 )
{
cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl;
}

/* Set Baud Rate */
cfsetospeed (&tty, B9600);
cfsetispeed (&tty, B9600);

/* Setting other Port Stuff */
tty.c_cflag     &=  ~PARENB;        // Make 8n1
tty.c_cflag     &=  ~CSTOPB;
tty.c_cflag     &=  ~CSIZE;
tty.c_cflag     |=  CS8;
tty.c_cflag     &=  ~CRTSCTS;       // no flow control
tty.c_lflag     =   0;          // no signaling chars, no echo, no canonical processing
tty.c_oflag     =   0;                  // no remapping, no delays
tty.c_cc[VMIN]      =   0;                  // read doesn't block
tty.c_cc[VTIME]     =   5;                  // 0.5 seconds read timeout

tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines
tty.c_iflag     &=  ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl
tty.c_lflag     &=  ~(ICANON | ECHO | ECHOE | ISIG); // make raw
tty.c_oflag     &=  ~OPOST;              // make raw

/* Flush Port, then applies attributes */
tcflush( USB, TCIFLUSH );

if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
cout << "Error " << errno << " from tcsetattr" << endl;
}

/* *** WRITE *** */

unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
int n_written = write( USB, cmd, sizeof(cmd) -1 );

/* Allocate memory for read buffer */
char buf [256];
memset (&buf, '\0', sizeof buf);

/* *** READ *** */
int n = read( USB, &buf , sizeof buf );

/* Error Handling */
if (n < 0)
{
     cout << "Error reading: " << strerror(errno) << endl;
}

/* Print what I read... */
cout << "Read: " << buf << endl;

close(USB);

会发生什么是 read() 返回0(根本没有读取字节)或阻塞直到超时( VTIME ) . 我假设发生这种情况是因为 write() 没有发送任何内容 . 在这种情况下,设备将不会收到命令,我无法收到响应 . 事实上,当我的程序在读取时被阻止时关闭设备实际上成功获得响应(设备在关闭时发送一些东西) .

奇怪的是,添加这个

cout << "I've written: " << n_written << "bytes" << endl;

write() 电话之后,我收到:

I've written 6 bytes

这正是我所期待的 . 只有我的程序不能正常工作,如端口上的 my device cannot receive what I'm actually writing .

我've tried different things and solution, also regarding data types (I'尝试过使用std :: string,例如 cmd = "INIT \r"const char ),但没有真正起作用 .

谁能告诉我哪里错了?

先感谢您 .

EDIT: 此代码的先前版本已使用

unsigned char cmd[] = "INIT \n"

还有 cmd[] = "INIT \r\n" . 我更改了它,因为我的设备的命令sintax被报告为

<command><SPACE><CR> .

我也试过在阅读时避免使用 O_NONBLOCK 标志,但是我只会阻止直到永远 . 我尝试过使用 select() 但没有任何反应 . 只是尝试一下,我创建了一个等待循环,直到数据可用,但我的代码永远不会退出循环 . 顺便说一句,等待或 usleep() 是我需要避免的 . 报告的只是我的代码的摘录 . Complete code needs to work in a real-time environment (特别是OROCOS)所以我真的不想要像睡眠一样的功能 .

3 回答

  • 0

    我已经解决了我的问题,所以我在这里发布正确的代码以防有人需要类似的东西 .

    Open Port

    int USB = open( "/dev/ttyUSB0", O_RDWR| O_NOCTTY );
    

    Set parameters

    struct termios tty;
    struct termios tty_old;
    memset (&tty, 0, sizeof tty);
    
    /* Error Handling */
    if ( tcgetattr ( USB, &tty ) != 0 ) {
       std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl;
    }
    
    /* Save old tty parameters */
    tty_old = tty;
    
    /* Set Baud Rate */
    cfsetospeed (&tty, (speed_t)B9600);
    cfsetispeed (&tty, (speed_t)B9600);
    
    /* Setting other Port Stuff */
    tty.c_cflag     &=  ~PARENB;            // Make 8n1
    tty.c_cflag     &=  ~CSTOPB;
    tty.c_cflag     &=  ~CSIZE;
    tty.c_cflag     |=  CS8;
    
    tty.c_cflag     &=  ~CRTSCTS;           // no flow control
    tty.c_cc[VMIN]   =  1;                  // read doesn't block
    tty.c_cc[VTIME]  =  5;                  // 0.5 seconds read timeout
    tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines
    
    /* Make raw */
    cfmakeraw(&tty);
    
    /* Flush Port, then applies attributes */
    tcflush( USB, TCIFLUSH );
    if ( tcsetattr ( USB, TCSANOW, &tty ) != 0) {
       std::cout << "Error " << errno << " from tcsetattr" << std::endl;
    }
    

    Write

    unsigned char cmd[] = "INIT \r";
    int n_written = 0,
        spot = 0;
    
    do {
        n_written = write( USB, &cmd[spot], 1 );
        spot += n_written;
    } while (cmd[spot-1] != '\r' && n_written > 0);
    

    绝对没有必要每字节写字节, int n_written = write( USB, cmd, sizeof(cmd) -1) 工作正常 .

    最后, read

    int n = 0,
        spot = 0;
    char buf = '\0';
    
    /* Whole response*/
    char response[1024];
    memset(response, '\0', sizeof response);
    
    do {
        n = read( USB, &buf, 1 );
        sprintf( &response[spot], "%c", buf );
        spot += n;
    } while( buf != '\r' && n > 0);
    
    if (n < 0) {
        std::cout << "Error reading: " << strerror(errno) << std::endl;
    }
    else if (n == 0) {
        std::cout << "Read nothing!" << std::endl;
    }
    else {
        std::cout << "Response: " << response << std::endl;
    }
    

    这个对我有用 . 谢谢你们!

  • 58

    有些接收器期望EOL序列,通常是两个字符 \r\n ,所以请尝试在代码中替换该行

    unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
    

    unsigned char cmd[] = "INIT\r\n";
    

    顺便说一句,上述方式可能更有效 . 没有必要引用每个角色 .

  • 0

    1)我在init之后添加一个/ n . 即写(USB,"init\n",5);

    2)仔细检查串口配置 . 赔率是不正确的 . 仅仅因为你没有使用^ Q / ^ S或硬件流控制并不意味着对方不期望它 .

    3) Most likely: 在写()后添加“usleep(100000); . 文件描述符设置为不阻塞或等待,对吗?在调用read之前需要多长时间才能获得响应?(它有在你可以读取它之前,通过系统硬件中断接收和缓冲内核 . )你是否考虑过使用select()等待读取内容()?可能是超时?

    Edited to Add:

    你需要DTR / RTS线吗?硬件流控制告诉对方发送计算机数据?例如

    int tmp, serialLines;
    
    cout << "Dropping Reading DTR and RTS\n";
    ioctl ( readFd, TIOCMGET, & serialLines );
    serialLines &= ~TIOCM_DTR;
    serialLines &= ~TIOCM_RTS;
    ioctl ( readFd, TIOCMSET, & serialLines );
    usleep(100000);
    ioctl ( readFd, TIOCMGET, & tmp );
    cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl;
    sleep (2);
    
    cout << "Setting Reading DTR and RTS\n";
    serialLines |= TIOCM_DTR;
    serialLines |= TIOCM_RTS;
    ioctl ( readFd, TIOCMSET, & serialLines );
    ioctl ( readFd, TIOCMGET, & tmp );
    cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl;
    

相关问题