繁体   English   中英

Linux上用C ++编写的串口。 可以在串口上读写同时发生..?

[英]Serial port in C++ on Linux. Can read and write on serial port happen simultaneously..?

我正在开发一个项目,需要一台Linux PC从UART上的微控制器获取数据,我已经在C ++ for Linux中使用了已经可用的串口开源代码。 (基于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连续出现的相同数据。 这是不刷新输入缓冲区的问题吗?

但我无法将数据从Linux PC发送到控制器,不知道发生了什么,可以在linux的串口上同时读写?

奇怪的是,当我在H-term(一个类似于超级终端的uART可视化器)打开端口时,我的串口代码在后端运行,仍然是H-term不会给出任何错误,但理想情况是H-术语应该给出一个错误,说“端口无法打开它被锁定”,但这不会发生,我的代码是不是在串口上获取锁定?

当我使用H-term连接端口并运行mu串口代码时,我可以看到UART上的数据从linux-PC到微控制器?

任何人都可以对我在这里遇到的问题有任何见解吗?

提前致谢。

一个问题在这里:

BufPos = fread((void*)ucResponse,1,10,fpSerial);

因为没有检查BufPos是零还是小于10

而不是ros :: ok,使用feof()(在接收0字节后)检查关闭连接,并使用ferror()检查错误。 或者当您知道(根据协议)已收到数据包时停止呼叫fread。

可以在全双工模式(即,读取和写入)中使用串行端口,而不是完全“同时”,而是可选地。 合作伙伴必须遵守协议以避免误解。

不要混合使用fprintf和fread / fwrite。 对于发送,指示fwrite。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM