Linux下C串行端口阅读/写作 [英] Linux C Serial Port Reading/Writing

查看:161
本文介绍了Linux下C串行端口阅读/写作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图发送/接收使用FTDI 通过USB端口的数据,所以我需要使用C / C ++来处理串行通信。我工作的的Linux (Ubuntu的)。

I'm trying to send/receive data over an USB Port using FTDI, so I need to handle serial communication using C/C++. I'm working on Linux (Ubuntu).

基本上,我连接到​​该监听传入的命令的设备。我需要发送这些命令和读取设备的响应。这两个命令和响应都是 ASCII字符

Basically, I am connected to a device which is listening for incoming commands. I need to send those commands and read device's response. Both commands and response are ASCII characters.

一切使用GtkTerm但是,当我切换到C编程,我遇到问题工作正常。

Everything works fine using GtkTerm but, when I switch to C programming, I encounter problems.

下面是我的code:

#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);

什么情况是,阅读()返回0(无字节读取所有)或阻塞,直到超时( VTIME )。我假设这是因为的write()不发送任何东西。在这种情况下,设备将不接收命令和不能接收响应。事实上,关闭设备我的程序被阻止在得到响应读数实际上succeded而(设备发送的东西,而关停)。

What happens is that read() returns 0 (no bytes read at all) or block until timeout (VTIME). I'm assuming this happens because write() does not send anything. In that case, device wouldn't receive command and I cannot receive response. In fact, turning off the device while my program is blocked on reading actually succeded in getting a response (device sends something while shutting down).

奇怪的是,添加此

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

的write()通话之后,我收到:

I've written 6 bytes

这就是我的期望。只有我的程序不能正常工作,因为它应该,例如我的设备无法接收什么,我实际编写端口。

我已经尝试不同的东西和解决方案,还对数据类型(我使用std :: string的尝试,如 CMD =INIT \\ R为const char ),但没有真正的工作。

I've tried different things and solution, also regarding data types (I've tried using std::string, such as cmd = "INIT \r" or const char) but nothing really worked.

谁能告诉我在哪里,我错了?

Can someone tell me where I'm wrong?

感谢您提前。

编辑:
这$ C $的C previously版本中使用

Previously version of this code used

unsigned char型CMD [] =INIT \\ N

和也 CMD [] =INIT \\ r \\ n。我改变了它,因为我的设备命令sintax被报告为

and also cmd[] = "INIT \r\n". I changed it because command sintax for my device is reported as

&LT;指挥GT;&lt;空&GT;&LT; CR&GT;

我也尝试避免在阅读 O_NONBLOCK 标记,但我只阻塞,直到永远。我已经使用选择()但没有任何反应尝试。只是一个尝试,我创建了一个等待循环,直到数据是avaliable,但是我的code从不退出循环。顺便说一句,等待或 usleep()函式是我需要避免。报道一个是只有我的code的摘录。 完整code需要在实时环境(特别OROCOS)的工作,所以我真的不希望睡眠之类的函数。

I've also tried avoiding the O_NONBLOCK flag on reading, but then I only block until forever. I've tried using select() but nothing happens. Just for a try, I've created a waiting loop until data is avaliable, but my code never exit the loop. Btw, waiting or usleep() is something I need to avoid. Reported one is only an excerpt of my code. Complete code needs to work in a real-time environment (specifically OROCOS) so I don't really want sleep-like function.

推荐答案

我已经解决了我的问题,所以我在这里张贴了正确的code,以防有人需要类似的东西。

I've solved my problems, so I post here the correct code in case someone needs similar stuff.

打开端口

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

设置参数

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;
}

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 =写(USB,CMD,sizeof的(CMD)-1)工作得很好。

最后,阅读

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;
}

这一次为我工作。谢谢大家!

This one worked for me. Thank you all!

这篇关于Linux下C串行端口阅读/写作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆