我正在开发一个项目,需要一台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部分留在一边,但问题在于串口代码。
当我运行这个代码时,我正确地接收到来自控制器的数据,但是即使控制器停止发送数据,我也会连续看到printf
上的相同数据。 这是不冲刷input缓冲区的问题?
但是我无法将数据从Linux PC发送到控制器,不知道发生了什么,可以在linux的串口上同时读写吗?
奇怪的是,当我在H端打开端口(与超级terminal相似的uART可视化器),并且我的串口代码在后端运行时,H-term仍然没有给出任何错误,但是理想情况下H-短语应该给出一个错误说“端口不能打开它被locking”,但是这并没有发生,是我的代码没有获得串口上的锁?
而当我连接使用H-term的端口与mu串行端口代码运行,然后我可以看到在从UART-PC到微控制器的UART上的数据?
任何人对我在这里面临的问题有什么看法吗?
提前致谢。
一个问题在这里:
BufPos = fread((void*)ucResponse,1,10,fpSerial);
因为没有检查BufPos是零还是小于10
而不是ros :: ok,使用feof()(在收到0字节后)检查一个关闭的连接,使用ferror()检查错误。 或者,当你知道(根据协议)已经接收到一个数据包时,停止调用fread。
在全双工模式(即读写)中使用串行端口不是完全“同时”,而是可选的。 合作伙伴必须遵循协议,以避免误解。
不要混用fprintf和fread / fwrite。 为了发送,指示了fwrite。