【发布时间】:2014-10-01 12:46:03
【问题描述】:
我正在做一个项目,该项目需要一台 Linux PC 从 UART 上的微控制器获取数据,为此我使用了一个已经可用的开源代码,用于 Linux 的 C++ 串行端口。 (基于Ros(机器人操作系统)的代码)
代码如下:
#define DEFAULT_BAUDRATE 115200
#define DEFAULT_SERIALPORT "/dev/ttyUSB0"
//Global data
FILE *fpSerial = NULL; //serial port file pointer
ros::Publisher ucResponseMsg;
ros::Subscriber ucCommandMsg;
int ucIndex; //ucontroller index number
int FileDesc;
unsigned char crc_sum=0;
//Initialize serial port, return file descriptor
FILE *serialInit(char * port, int baud)
{
int BAUD = 0;
int fd = -1;
struct termios newtio, oldtio;
FILE *fp = NULL;
//Open the serial port as a file descriptor for low level configuration
// read/write, not controlling terminal for process,
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
ROS_INFO("FileDesc : %d",fd);
if ( fd<0 )
{
ROS_ERROR("serialInit: Could not open serial device %s",port);
return fp;
}
// save current serial port settings
tcgetattr(fd,&oldtio);
// clear the struct for new port settings
bzero(&newtio, sizeof(newtio));
//Look up appropriate baud rate constant
switch (baud)
{
case 38400:
default:
BAUD = B38400;
break;
case 19200:
BAUD = B19200;
break;
case 115200:
BAUD = B115200;
break;
case 9600:
BAUD = B9600;
break;
case 4800:
BAUD = B4800;
break;
case 2400:
BAUD = B2400;
break;
case 1800:
BAUD = B1800;
break;
case 1200:
BAUD = B1200;
break;
} //end of switch baud_rate
if (cfsetispeed(&newtio, BAUD) < 0 || cfsetospeed(&newtio, BAUD) < 0)
{
ROS_ERROR("serialInit: Failed to set serial baud rate: %d", baud);
close(fd);
return NULL;
}
// set baud rate, (8bit,noparity, 1 stopbit), local control, enable receiving characters.
newtio.c_cflag = BAUD | CRTSCTS | CS8 | CLOCAL | CREAD;
// ignore bytes with parity errors
newtio.c_iflag = IGNPAR;
// raw output
newtio.c_oflag = 0;
// set input mode to non - canonical
newtio.c_lflag = 0;
// inter-charcter timer
newtio.c_cc[VTIME] = 0;
// blocking read (blocks the read until the no.of charcters are read
newtio.c_cc[VMIN] = 0;
// clean the line and activate the settings for the port
tcflush(fd, TCIFLUSH);
tcsetattr (fd, TCSANOW,&newtio);
//Open file as a standard I/O stream
fp = fdopen(fd, "r+");
if (!fp) {
ROS_ERROR("serialInit: Failed to open serial stream %s", port);
fp = NULL;
}
ROS_INFO("FileStandard I/O stream: %d",fp);
return fp;
} //serialInit
//Process ROS command message, send to uController
void ucCommandCallback(const geometry_msgs::TwistConstPtr& cmd_vel)
{
unsigned char msg[14];
float test1,test2;
unsigned long i;
// build the message packet to be sent
msg = packet to be sent;
msg[13] = crc_sum;
for (i=0;i<14;i++)
{
fprintf(fpSerial, "%c", msg[i]);
}
tcflush(FileDesc, TCOFLUSH);
} //ucCommandCallback
//Receive command responses from robot uController
//and publish as a ROS message
void *rcvThread(void *arg)
{
int rcvBufSize = 200;
char ucResponse[10];//[rcvBufSize]; //response string from uController
char *bufPos;
std_msgs::String msg;
std::stringstream ss;
int BufPos,i;
unsigned char crc_rx_sum =0;
while (ros::ok()) {
BufPos = fread((void*)ucResponse,1,10,fpSerial);
for (i=0;i<10;i++)
{
ROS_INFO("T: %x ",(unsigned char)ucResponse[i]);
ROS_INFO("NT: %x ",ucResponse[i]);
}
msg.data = ucResponse;
ucResponseMsg.publish(msg);
}
return NULL;
} //rcvThread
int main(int argc, char **argv)
{
char port[20]; //port name
int baud; //baud rate
char topicSubscribe[20];
char topicPublish[20];
pthread_t rcvThrID; //receive thread ID
int err;
//Initialize ROS
ros::init(argc, argv, "r2SerialDriver");
ros::NodeHandle rosNode;
ROS_INFO("r2Serial starting");
//Open and initialize the serial port to the uController
if (argc > 1) {
if(sscanf(argv[1],"%d", &ucIndex)==1) {
sprintf(topicSubscribe, "uc%dCommand",ucIndex);
sprintf(topicPublish, "uc%dResponse",ucIndex);
}
else {
ROS_ERROR("ucontroller index parameter invalid");
return 1;
}
}
else {
strcpy(topicSubscribe, "uc0Command");
strcpy(topicPublish, "uc0Response");
}
strcpy(port, DEFAULT_SERIALPORT);
if (argc > 2)
strcpy(port, argv[2]);
baud = DEFAULT_BAUDRATE;
if (argc > 3) {
if(sscanf(argv[3],"%d", &baud)!=1) {
ROS_ERROR("ucontroller baud rate parameter invalid");
return 1;
}
}
ROS_INFO("connection initializing (%s) at %d baud", port, baud);
fpSerial = serialInit(port, baud);
if (!fpSerial )
{
ROS_ERROR("unable to create a new serial port");
return 1;
}
ROS_INFO("serial connection successful");
//Subscribe to ROS messages
ucCommandMsg = rosNode.subscribe("cmd_vel" /*topicSubscribe*/, 100, ucCommandCallback);
//Setup to publish ROS messages
ucResponseMsg = rosNode.advertise<std_msgs::String>(topicPublish, 100);
//Create receive thread
err = pthread_create(&rcvThrID, NULL, rcvThread, NULL);
if (err != 0) {
ROS_ERROR("unable to create receive thread");
return 1;
}
//Process ROS messages and send serial commands to uController
ros::spin();
fclose(fpSerial);
ROS_INFO("r2Serial stopping");
return 0;
}
你可以把ROS部分放在一边,但问题出在串口代码上。
当我运行此代码时,我会正确接收来自控制器的数据,但即使控制器停止发送数据,我也会看到printfs 上不断出现相同的数据。这是不刷新输入缓冲区的问题吗?
但是我无法将数据从Linux PC发送到控制器,不知道发生了什么,Linux中的串口可以同时读写吗?
奇怪的观察,当我在 H-term(类似于超级终端的 uART 可视化器)中打开端口并且我的串行端口代码在后端运行时,H-term 仍然没有给出任何错误,但是理想情况下,H-term 应该给出一个错误,说“端口无法打开它被锁定”,但这不会发生,我的代码是否没有在串行端口上获得锁定?
当我使用 H-term 连接端口并运行 mu 串行端口代码时,我可以看到 UART 上从 linux-PC 到微控制器的数据?
任何人都可以对我在这里面临的问题有任何见解吗?
提前致谢。
【问题讨论】:
-
我也遇到过类似的问题。确保数据被刷新等等。除此之外,我已经看到 UART 通信的稳定性可以与波特率相关联。另外,请查看github.com/freemed/tty0tty,它对于解决此类问题非常有用。
-
Data Flushed 的意思,请您详细说明一下。
-
当您使用
fprintf时,数据不会被写入,直到您打印换行符或执行 fflush。 -
还有其他问题吗?
-
不,我现在正在使用 fwrite(跟随@laune 评论)。
标签: c++ linux serialization