我是靠谱客的博主 壮观马里奥,最近开发中收集的这篇文章主要介绍Linux下串口信息的读取,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在Linux下串口信息的读取有了一点心得体会。

 

  1. 打开串口

 

  与其他的关于设备编程的方法一样,在Linux下,操作、控制串口也是通过操作起设备文件进行的。在Linux下,串口的设备文件是/dev/ttyS0或/dev/ttyS1等。因此要读写串口,我们首先要打开串口:

 

  char *dev = "/dev/ttyS0"; //串口1

 

  int fd = open( dev, O_RDWR );

 

  //| O_NOCTTY | O_NDELAY

 

  if (-1 == fd)

 

  {

 

  perror("Can't Open Serial Port");

 

  return -1;

 

  }

 

  else

 

  return fd;

 

  2. 设置串口速度

 

  打开串口成功后,我们就可以对其进行读写了。首先要设置串口的波特率:

 

  int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,

 

  B38400, B19200, B9600, B4800, B2400, B1200, B300, };

 

  int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,

 

  19200, 9600, 4800, 2400, 1200, 300, };

 

  void set_speed(int fd, int speed){

 

  int i;

 

  int status;

 

  struct termios Opt;

 

  tcgetattr(fd, &Opt);

 

  for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {

 

  if (speed == name_arr) {

 

  tcflush(fd, TCIOFLUSH);

 

  cfsetispeed(&Opt, speed_arr);

 

  cfsetospeed(&Opt, speed_arr);

 

  status = tcsetattr(fd, TCSANOW, &Opt);

 

  if (status != 0) {

 

  perror("tcsetattr fd");

 

  return;

 

  }

 

  tcflush(fd,TCIOFLUSH);

 

  }

 

  }

 

  }

 

  3. 设置串口信息

 

  这主要包括:数据位、停止位、奇偶校验位这些主要的信息。

 

  /**

 

  *@brief 设置串口数据位,停止位和效验位

 

  *@param fd 类型 int 打开的串口文件句柄

 

  *@param databits 类型 int 数据位 取值 为 7 或者8

 

  *@param stopbits 类型 int 停止位 取值为 1 或者2

 

  *@param parity 类型 int 效验类型 取值为N,E,O,,S

 

  */

 

  int set_Parity(int fd,int databits,int stopbits,int parity)

 

  {

 

  struct termios options;

 

  if ( tcgetattr( fd,&options) != 0) {

 

  perror("SetupSerial 1");

 

  return(FALSE);

 

  }

 

  options.c_cflag &= ~CSIZE;

 

  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/

 

  options.c_oflag &= ~OPOST; /*Output*/

 

  switch (databits) /*设置数据位数*/

 

  {

 

  case 7:

 

  options.c_cflag |= CS7;

 

  break;

 

  case 8:

 

  options.c_cflag |= CS8;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported data sizen"); return (FALSE);

 

  }

 

  switch (parity)

 

  {

 

  case 'n':

 

  case 'N':

 

  options.c_cflag &= ~PARENB; /* Clear parity enable */

 

  options.c_iflag &= ~INPCK; /* Enable parity checking */

 

  break;

 

  case 'o':

 

  case 'O':

 

  options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'e':

 

  case 'E':

 

  options.c_cflag |= PARENB; /* Enable parity */

 

  options.c_cflag &= ~PARODD; /* 转换为偶效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'S':

 

  case 's': /*as no parity*/

 

  options.c_cflag &= ~PARENB;

 

  options.c_cflag &= ~CSTOPB;break;

 

  default:

 

  fprintf(stderr,"Unsupported parityn");

 

  return (FALSE);

 

  }

 

  /* 设置停止位*/

 

  switch (stopbits)

 

  {

 

  case 1:

 

  options.c_cflag &= ~CSTOPB;

 

  break;

 

  case 2:

 

  options.c_cflag |= CSTOPB;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported stop bitsn");

 

  return (FALSE);

 

  }

 

  /* Set input parity option */

 

  if (parity != 'n')

 

  options.c_iflag |= INPCK;

 

  tcflush(fd,TCIFLUSH);

 

  options.c_cc[VTIME] = 0; /* 设置超时0 seconds*/

 

  options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

 

  if (tcsetattr(fd,TCSANOW,&options) != 0)

 

  {

 

  perror("SetupSerial 3");

 

  return (FALSE);

 

  }

 

  return (TRUE);

 

  }

 

  在上述代码中,有两句话特别重要:

 

  options.c_cc[VTIME] = 0; /* 设置超时0 seconds*/

 

  options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

 

  这两句话决定了对串口读取的函数read()的一些功能。我将着重介绍一下他们对read()函数的影响。

 

  对串口操作的结构体是

 

  Struct{

 

  tcflag_t c_iflag; /*输入模式标记*/

 

  tcflag_t c_oflag; /*输出模式标记*/

 

  tcflag_t c_cflag; /*控制模式标记*/

 

  tcflag_t c_lflag; /*本地模式标记*/

 

  cc_t c_line; /*线路规程*/

 

  cc_t c_cc[NCCS]; /*控制符号*/

 

  };

 

  其中cc_t c_line只有在一些特殊的系统程序(比如,设置通过tty设备来通信的网络协议)中才会用。在数组c_cc中有两个下标(VTIME和VMIN)对应的元素不是控制符,并且只是在原始模式下有效。只有在原始模式下,他们决定了read()函数在什么时候返回。在标准模式下,除非设置了O_NONBLOCK选项,否则只有当遇到文件结束符或各行的字符都已经编辑完毕后才返回。

 

  控制符VTIME和VMIN之间有着复杂的关系。VTIME定义要求等待的零到几百毫秒的时间量(通常是一个8位的unsigned char变量,取值不能大于cc_t)。VMIN定义了要求等待的最小字节数(不是要求读的字节数——read()的第三个参数才是指定要求读的最大字节数),这个字节数可能是0.

 

  l 如果VTIME取0,VMIN定义了要求等待读取的最小字节数。函数read()只有在读取了VMIN个字节的数据或者收到一个信号的时候才返回。

 

  l 如果VMIN取0,VTIME定义了即使没有数据可以读取,read()函数返回前也要等待几百毫秒的时间量。这时,read()函数不需要像其通常情况那样要遇到一个文件结束标志才返回0.

 

  l 如果VTIME和VMIN都不取0,VTIME定义的是当接收到第一个字节的数据后开始计算等待的时间量。如果当调用read函数时可以得到数据,计时器马上开始计时。如果当调用read函数时还没有任何数据可读,则等接收到第一个字节的数据后,计时器开始计时。函数read可能会在读取到VMIN个字节的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。

 

  l 如果VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回。同时,返回值0表示read函数不需要等待文件结束标志就返回了。

 

  这就是这两个变量对read函数的影响。我使用的读卡器每次传送的数据是13个字节,一开始,我把它们设置成

 

  options.c_cc[VTIME] = 150

 

  options.c_cc[VMIN] = 0;

 

  结果,每次读取的信息只有8个字节,剩下的5个字节要等到下一次打卡时才能收到。就是由于这个原因造成的。根据上面规则的第一条,我把VTIME取0,VMIN=13,也就是正好等于一次需要接收的字节数。这样就实现了一次读取13个字节值。同时,得出这样的结论,如果读卡器送出的数据为n个字节,那么就把VMIN=n,这样一次读取的信息正好为读卡器送出的信息,并且读取的时候不需要进行循环读取。

 

  4. 读取数据

 

  有了上面的函数后,我设置了串口的基本信息,根据我们自己的实际情况,设置了相应的参数,就可以读取数据了。

 

  void getcardinfo(char *buff){

 

  int fd;

 

  int nread,count=0;

 

  char tempbuff[13];

 

  char *dev = "/dev/ttyS0"; //串口1

 

  fd = OpenDev(dev);

 

  set_speed(fd,9600);

 

  if (set_Parity(fd,8,1,'N') == FALSE) {

 

  printf("Set Parity Errorn");

 

  //return -1;

 

  }

 

  while (1) //循环读取数据

 

  {

 

  count=0;

 

  //sleep(5000);

 

  while(1)

 

  {

 

  if((nread = read(fd, tempbuff, 13))>0)

 

  {

 

  //printf("nLen %dn",nread);

 

  memcpy(&buff[count],tempbuff,nread);

 

  count+=nread;

 

  }

 

  if(count==13)

 

  {

 

  buff[count+1] = '';

 

  //printf( "n%s", buff);

 

  break;

 

  }

 

  }

 

  //break;

 

  }

 

  //return buff;

 

  close(fd);

 

  pthread_exit(NULL);

 

  //close(fd);

 

  // exit (0);

 

  }

 

  这是我原来的程序,其实把VMIN设置以后,可以改成:

 

  void getcardinfo(char *buff){

 

  int fd;

 

  int nread,count=0;

 

  char tempbuff[13];

 

  char *dev = "/dev/ttyS0"; //串口1

 

  fd = OpenDev(dev);

 

  set_speed(fd,9600);

 

  if (set_Parity(fd,8,1,'N') == FALSE) {

 

  printf("Set Parity Errorn");

 

  //return -1;

 

  }

 

  nread = read(fd, buff, 13)

 

  close(fd);

 

  }

 

  5. 程序完整代码:

 

  #include /*标准输入输出定义*/

 

  #include /*标准函数库定义*/

 

  #include /*Unix 标准函数定义*/

 

  #include

 

  #include

 

  #include /*文件控制定义*/

 

  #include /*PPSIX 终端控制定义*/

 

  #include /*错误号定义*/

 

  #define FALSE -1

 

  #define TRUE 0

 

  /**

 

  *@brief 设置串口通信速率

 

  *@param fd 类型 int 打开串口的文件句柄

 

  *@param speed 类型 int 串口速度

 

  *@return void

 

  */

 

  int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,

 

  B38400, B19200, B9600, B4800, B2400, B1200, B300, };

 

  int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,

 

  19200, 9600, 4800, 2400, 1200, 300, };

 

  void set_speed(int fd, int speed){

 

  int i;

 

  int status;

 

  struct termios Opt;

 

  tcgetattr(fd, &Opt);

 

  for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {

 

  if (speed == name_arr) {

 

  tcflush(fd, TCIOFLUSH);

 

  cfsetispeed(&Opt, speed_arr);

 

  cfsetospeed(&Opt, speed_arr);

 

  status = tcsetattr(fd, TCSANOW, &Opt);

 

  if (status != 0) {

 

  perror("tcsetattr fd");

 

  return;

 

  }

 

  tcflush(fd,TCIOFLUSH);

 

  }

 

  }

 

  }

 

  /**

 

  *@brief 设置串口数据位,停止位和效验位

 

  *@param fd 类型 int 打开的串口文件句柄

 

  *@param databits 类型 int 数据位 取值 为 7 或者8

 

  *@param stopbits 类型 int 停止位 取值为 1 或者2

 

  *@param parity 类型 int 效验类型 取值为N,E,O,,S

 

  */

 

  int set_Parity(int fd,int databits,int stopbits,int parity)

 

  {

 

  struct termios options;

 

  if ( tcgetattr( fd,&options) != 0) {

 

  perror("SetupSerial 1");

 

  return(FALSE);

 

  }

 

  options.c_cflag &= ~CSIZE;

 

  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/

 

  options.c_oflag &= ~OPOST; /*Output*/

 

  switch (databits) /*设置数据位数*/

 

  {

 

  case 7:

 

  options.c_cflag |= CS7;

 

  break;

 

  case 8:

 

  options.c_cflag |= CS8;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported data sizen"); return (FALSE);

 

  }

 

  switch (parity)

 

  {

 

  case 'n':

 

  case 'N':

 

  options.c_cflag &= ~PARENB; /* Clear parity enable */

 

  options.c_iflag &= ~INPCK; /* Enable parity checking */

 

  break;

 

  case 'o':

 

  case 'O':

 

  options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'e':

 

  case 'E':

 

  options.c_cflag |= PARENB; /* Enable parity */

 

  options.c_cflag &= ~PARODD; /* 转换为偶效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'S':

 

  case 's': /*as no parity*/

 

  options.c_cflag &= ~PARENB;

 

  options.c_cflag &= ~CSTOPB;break;

 

  default:

 

  fprintf(stderr,"Unsupported parityn");

 

  return (FALSE);

 

  }

 

  /* 设置停止位*/

 

  switch (stopbits)

 

  {

 

  case 1:

 

  options.c_cflag &= ~CSTOPB;

 

  break;

 

  case 2:

 

  options.c_cflag |= CSTOPB;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported stop bitsn");

 

  return (FALSE);

 

  }

 

  /* Set input parity option */

 

  if (parity != 'n')

 

  options.c_iflag |= INPCK;

 

  tcflush(fd,TCIFLUSH);

 

  options.c_cc[VTIME] = 0; /* 设置超时15 seconds*/

 

  options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

 

  if (tcsetattr(fd,TCSANOW,&options) != 0)

 

  {

 

  perror("SetupSerial 3");

 

  return (FALSE);

 

  }

 

  return (TRUE);

 

  }

 

  /**********************************************************************

 

  代码说明:使用串口一测试的,发送的数据是字符,

 

  但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号

 

  **********************************************************************/

 

  /*********************************************************************/

 

  int OpenDev(char *Dev)

 

  {

 

  int fd = open( Dev, O_RDWR );

 

  //| O_NOCTTY | O_NDELAY

 

  if (-1 == fd)

 

  {

 

  perror("Can't Open Serial Port");

 

  return -1;

 

  }

 

  else

 

  return fd;

 

  }

 

  void getcardinfo(char *buff){

 

  int fd;

 

  int nread,count=0;

 

  char tempbuff[13];

 

  char *dev = "/dev/ttyS0"; //串口1

 

  fd = OpenDev(dev);

 

  set_speed(fd,9600);

 

  if (set_Parity(fd,8,1,'N') == FALSE) {

 

  printf("Set Parity Errorn");

 

  //return -1;

 

  }

 

  while (1) //循环读取数据

 

  {

 

  count=0;

 

  //sleep(5000);

 

  while(1)

 

  {

 

  if((nread = read(fd, tempbuff, 13))>0)

 

  {

 

  //printf("nLen %dn",nread);

 

  memcpy(&buff[count],tempbuff,nread);

 

  count+=nread;

 

  }

 

  if(count==13)

 

  {

 

  buff[count+1] = '';

 

  //printf( "n%s", buff);

 

  break;

 

  }

 

  }

 

  //break;

 

  }

 

  //return buff;

 

  close(fd);

 

  pthread_exit(NULL);

 

  //close(fd);

 

  // exit (0);

 

  } 本文作者:在Linux下串口信息的读取有了一点心得体会。

 

  1. 打开串口

 

  与其他的关于设备编程的方法一样,在Linux下,操作、控制串口也是通过操作起设备文件进行的。在Linux下,串口的设备文件是/dev/ttyS0或/dev/ttyS1等。因此要读写串口,我们首先要打开串口:

 

  char *dev = "/dev/ttyS0"; //串口1

 

  int fd = open( dev, O_RDWR );

 

  //| O_NOCTTY | O_NDELAY

 

  if (-1 == fd)

 

  {

 

  perror("Can't Open Serial Port");

 

  return -1;

 

  }

 

  else

 

  return fd;

 

  2. 设置串口速度

 

  打开串口成功后,我们就可以对其进行读写了。首先要设置串口的波特率:

 

  int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,

 

  B38400, B19200, B9600, B4800, B2400, B1200, B300, };

 

  int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,

 

  19200, 9600, 4800, 2400, 1200, 300, };

 

  void set_speed(int fd, int speed){

 

  int i;

 

  int status;

 

  struct termios Opt;

 

  tcgetattr(fd, &Opt);

 

  for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {

 

  if (speed == name_arr) {

 

  tcflush(fd, TCIOFLUSH);

 

  cfsetispeed(&Opt, speed_arr);

 

  cfsetospeed(&Opt, speed_arr);

 

  status = tcsetattr(fd, TCSANOW, &Opt);

 

  if (status != 0) {

 

  perror("tcsetattr fd");

 

  return;

 

  }

 

  tcflush(fd,TCIOFLUSH);

 

  }

 

  }

 

  }

 

  3. 设置串口信息

 

  这主要包括:数据位、停止位、奇偶校验位这些主要的信息。

 

  /**

 

  *@brief 设置串口数据位,停止位和效验位

 

  *@param fd 类型 int 打开的串口文件句柄

 

  *@param databits 类型 int 数据位 取值 为 7 或者8

 

  *@param stopbits 类型 int 停止位 取值为 1 或者2

 

  *@param parity 类型 int 效验类型 取值为N,E,O,,S

 

  */

 

  int set_Parity(int fd,int databits,int stopbits,int parity)

 

  {

 

  struct termios options;

 

  if ( tcgetattr( fd,&options) != 0) {

 

  perror("SetupSerial 1");

 

  return(FALSE);

 

  }

 

  options.c_cflag &= ~CSIZE;

 

  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/

 

  options.c_oflag &= ~OPOST; /*Output*/

 

  switch (databits) /*设置数据位数*/

 

  {

 

  case 7:

 

  options.c_cflag |= CS7;

 

  break;

 

  case 8:

 

  options.c_cflag |= CS8;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported data sizen"); return (FALSE);

 

  }

 

  switch (parity)

 

  {

 

  case 'n':

 

  case 'N':

 

  options.c_cflag &= ~PARENB; /* Clear parity enable */

 

  options.c_iflag &= ~INPCK; /* Enable parity checking */

 

  break;

 

  case 'o':

 

  case 'O':

 

  options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'e':

 

  case 'E':

 

  options.c_cflag |= PARENB; /* Enable parity */

 

  options.c_cflag &= ~PARODD; /* 转换为偶效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'S':

 

  case 's': /*as no parity*/

 

  options.c_cflag &= ~PARENB;

 

  options.c_cflag &= ~CSTOPB;break;

 

  default:

 

  fprintf(stderr,"Unsupported parityn");

 

  return (FALSE);

 

  }

 

  /* 设置停止位*/

 

  switch (stopbits)

 

  {

 

  case 1:

 

  options.c_cflag &= ~CSTOPB;

 

  break;

 

  case 2:

 

  options.c_cflag |= CSTOPB;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported stop bitsn");

 

  return (FALSE);

 

  }

 

  /* Set input parity option */

 

  if (parity != 'n')

 

  options.c_iflag |= INPCK;

 

  tcflush(fd,TCIFLUSH);

 

  options.c_cc[VTIME] = 0; /* 设置超时0 seconds*/

 

  options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

 

  if (tcsetattr(fd,TCSANOW,&options) != 0)

 

  {

 

  perror("SetupSerial 3");

 

  return (FALSE);

 

  }

 

  return (TRUE);

 

  }

 

  在上述代码中,有两句话特别重要:

 

  options.c_cc[VTIME] = 0; /* 设置超时0 seconds*/

 

  options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

 

  这两句话决定了对串口读取的函数read()的一些功能。我将着重介绍一下他们对read()函数的影响。

 

  对串口操作的结构体是

 

  Struct{

 

  tcflag_t c_iflag; /*输入模式标记*/

 

  tcflag_t c_oflag; /*输出模式标记*/

 

  tcflag_t c_cflag; /*控制模式标记*/

 

  tcflag_t c_lflag; /*本地模式标记*/

 

  cc_t c_line; /*线路规程*/

 

  cc_t c_cc[NCCS]; /*控制符号*/

 

  };

 

  其中cc_t c_line只有在一些特殊的系统程序(比如,设置通过tty设备来通信的网络协议)中才会用。在数组c_cc中有两个下标(VTIME和VMIN)对应的元素不是控制符,并且只是在原始模式下有效。只有在原始模式下,他们决定了read()函数在什么时候返回。在标准模式下,除非设置了O_NONBLOCK选项,否则只有当遇到文件结束符或各行的字符都已经编辑完毕后才返回。

 

  控制符VTIME和VMIN之间有着复杂的关系。VTIME定义要求等待的零到几百毫秒的时间量(通常是一个8位的unsigned char变量,取值不能大于cc_t)。VMIN定义了要求等待的最小字节数(不是要求读的字节数——read()的第三个参数才是指定要求读的最大字节数),这个字节数可能是0.

 

  l 如果VTIME取0,VMIN定义了要求等待读取的最小字节数。函数read()只有在读取了VMIN个字节的数据或者收到一个信号的时候才返回。

 

  l 如果VMIN取0,VTIME定义了即使没有数据可以读取,read()函数返回前也要等待几百毫秒的时间量。这时,read()函数不需要像其通常情况那样要遇到一个文件结束标志才返回0.

 

  l 如果VTIME和VMIN都不取0,VTIME定义的是当接收到第一个字节的数据后开始计算等待的时间量。如果当调用read函数时可以得到数据,计时器马上开始计时。如果当调用read函数时还没有任何数据可读,则等接收到第一个字节的数据后,计时器开始计时。函数read可能会在读取到VMIN个字节的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。

 

  l 如果VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回。同时,返回值0表示read函数不需要等待文件结束标志就返回了。

 

  这就是这两个变量对read函数的影响。我使用的读卡器每次传送的数据是13个字节,一开始,我把它们设置成

 

  options.c_cc[VTIME] = 150

 

  options.c_cc[VMIN] = 0;

 

  结果,每次读取的信息只有8个字节,剩下的5个字节要等到下一次打卡时才能收到。就是由于这个原因造成的。根据上面规则的第一条,我把VTIME取0,VMIN=13,也就是正好等于一次需要接收的字节数。这样就实现了一次读取13个字节值。同时,得出这样的结论,如果读卡器送出的数据为n个字节,那么就把VMIN=n,这样一次读取的信息正好为读卡器送出的信息,并且读取的时候不需要进行循环读取。

 

  4. 读取数据

 

  有了上面的函数后,我设置了串口的基本信息,根据我们自己的实际情况,设置了相应的参数,就可以读取数据了。

 

  void getcardinfo(char *buff){

 

  int fd;

 

  int nread,count=0;

 

  char tempbuff[13];

 

  char *dev = "/dev/ttyS0"; //串口1

 

  fd = OpenDev(dev);

 

  set_speed(fd,9600);

 

  if (set_Parity(fd,8,1,'N') == FALSE) {

 

  printf("Set Parity Errorn");

 

  //return -1;

 

  }

 

  while (1) //循环读取数据

 

  {

 

  count=0;

 

  //sleep(5000);

 

  while(1)

 

  {

 

  if((nread = read(fd, tempbuff, 13))>0)

 

  {

 

  //printf("nLen %dn",nread);

 

  memcpy(&buff[count],tempbuff,nread);

 

  count+=nread;

 

  }

 

  if(count==13)

 

  {

 

  buff[count+1] = '';

 

  //printf( "n%s", buff);

 

  break;

 

  }

 

  }

 

  //break;

 

  }

 

  //return buff;

 

  close(fd);

 

  pthread_exit(NULL);

 

  //close(fd);

 

  // exit (0);

 

  }

 

  这是我原来的程序,其实把VMIN设置以后,可以改成:

 

  void getcardinfo(char *buff){

 

  int fd;

 

  int nread,count=0;

 

  char tempbuff[13];

 

  char *dev = "/dev/ttyS0"; //串口1

 

  fd = OpenDev(dev);

 

  set_speed(fd,9600);

 

  if (set_Parity(fd,8,1,'N') == FALSE) {

 

  printf("Set Parity Errorn");

 

  //return -1;

 

  }

 

  nread = read(fd, buff, 13)

 

  close(fd);

 

  }

 

  5. 程序完整代码:

 

  #include /*标准输入输出定义*/

 

  #include /*标准函数库定义*/

 

  #include /*Unix 标准函数定义*/

 

  #include

 

  #include

 

  #include /*文件控制定义*/

 

  #include /*PPSIX 终端控制定义*/

 

  #include /*错误号定义*/

 

  #define FALSE -1

 

  #define TRUE 0

 

  /**

 

  *@brief 设置串口通信速率

 

  *@param fd 类型 int 打开串口的文件句柄

 

  *@param speed 类型 int 串口速度

 

  *@return void

 

  */

 

  int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,

 

  B38400, B19200, B9600, B4800, B2400, B1200, B300, };

 

  int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,

 

  19200, 9600, 4800, 2400, 1200, 300, };

 

  void set_speed(int fd, int speed){

 

  int i;

 

  int status;

 

  struct termios Opt;

 

  tcgetattr(fd, &Opt);

 

  for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {

 

  if (speed == name_arr) {

 

  tcflush(fd, TCIOFLUSH);

 

  cfsetispeed(&Opt, speed_arr);

 

  cfsetospeed(&Opt, speed_arr);

 

  status = tcsetattr(fd, TCSANOW, &Opt);

 

  if (status != 0) {

 

  perror("tcsetattr fd");

 

  return;

 

  }

 

  tcflush(fd,TCIOFLUSH);

 

  }

 

  }

 

  }

 

  /**

 

  *@brief 设置串口数据位,停止位和效验位

 

  *@param fd 类型 int 打开的串口文件句柄

 

  *@param databits 类型 int 数据位 取值 为 7 或者8

 

  *@param stopbits 类型 int 停止位 取值为 1 或者2

 

  *@param parity 类型 int 效验类型 取值为N,E,O,,S

 

  */

 

  int set_Parity(int fd,int databits,int stopbits,int parity)

 

  {

 

  struct termios options;

 

  if ( tcgetattr( fd,&options) != 0) {

 

  perror("SetupSerial 1");

 

  return(FALSE);

 

  }

 

  options.c_cflag &= ~CSIZE;

 

  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/

 

  options.c_oflag &= ~OPOST; /*Output*/

 

  switch (databits) /*设置数据位数*/

 

  {

 

  case 7:

 

  options.c_cflag |= CS7;

 

  break;

 

  case 8:

 

  options.c_cflag |= CS8;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported data sizen"); return (FALSE);

 

  }

 

  switch (parity)

 

  {

 

  case 'n':

 

  case 'N':

 

  options.c_cflag &= ~PARENB; /* Clear parity enable */

 

  options.c_iflag &= ~INPCK; /* Enable parity checking */

 

  break;

 

  case 'o':

 

  case 'O':

 

  options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'e':

 

  case 'E':

 

  options.c_cflag |= PARENB; /* Enable parity */

 

  options.c_cflag &= ~PARODD; /* 转换为偶效验*/

 

  options.c_iflag |= INPCK; /* Disnable parity checking */

 

  break;

 

  case 'S':

 

  case 's': /*as no parity*/

 

  options.c_cflag &= ~PARENB;

 

  options.c_cflag &= ~CSTOPB;break;

 

  default:

 

  fprintf(stderr,"Unsupported parityn");

 

  return (FALSE);

 

  }

 

  /* 设置停止位*/

 

  switch (stopbits)

 

  {

 

  case 1:

 

  options.c_cflag &= ~CSTOPB;

 

  break;

 

  case 2:

 

  options.c_cflag |= CSTOPB;

 

  break;

 

  default:

 

  fprintf(stderr,"Unsupported stop bitsn");

 

  return (FALSE);

 

  }

 

  /* Set input parity option */

 

  if (parity != 'n')

 

  options.c_iflag |= INPCK;

 

  tcflush(fd,TCIFLUSH);

 

  options.c_cc[VTIME] = 0; /* 设置超时15 seconds*/

 

  options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/

 

  if (tcsetattr(fd,TCSANOW,&options) != 0)

 

  {

 

  perror("SetupSerial 3");

 

  return (FALSE);

 

  }

 

  return (TRUE);

 

  }

 

  /**********************************************************************

 

  代码说明:使用串口一测试的,发送的数据是字符,

 

  但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号

 

  **********************************************************************/

 

  /*********************************************************************/

 

  int OpenDev(char *Dev)

 

  {

 

  int fd = open( Dev, O_RDWR );

 

  //| O_NOCTTY | O_NDELAY

 

  if (-1 == fd)

 

  {

 

  perror("Can't Open Serial Port");

 

  return -1;

 

  }

 

  else

 

  return fd;

 

  }

 

  void getcardinfo(char *buff){

 

  int fd;

 

  int nread,count=0;

 

  char tempbuff[13];

 

  char *dev = "/dev/ttyS0"; //串口1

 

  fd = OpenDev(dev);

 

  set_speed(fd,9600);

 

  if (set_Parity(fd,8,1,'N') == FALSE) {

 

  printf("Set Parity Errorn");

 

  //return -1;

 

  }

 

  while (1) //循环读取数据

 

  {

 

  count=0;

 

  //sleep(5000);

 

  while(1)

 

  {

 

  if((nread = read(fd, tempbuff, 13))>0)

 

  {

 

  //printf("nLen %dn",nread);

 

  memcpy(&buff[count],tempbuff,nread);

 

  count+=nread;

 

  }

 

  if(count==13)

 

  {

 

  buff[count+1] = '';

 

  //printf( "n%s", buff);

 

  break;

 

  }

 

  }

 

  //break;

 

  }

 

  //return buff;

 

  close(fd);

 

  pthread_exit(NULL);

 

  //close(fd);

 

  // exit (0);

 

  }

//改为:

//SerialPort.h

#pragma once

#include <string>

#include <termios.h>

#include <functional>

#include <vector>

typedef std::function<void(std::vector<uint8_t>&)> OnReadSerialPortDataCallBack;

class SerialPort

{

public:

SerialPort();

~SerialPort();

bool OpenPort(const std::string &portName, const OnReadSerialPortDataCallBack &cb);

void ClosePort();

int WriteData(const char* buf, int len);

int set_port_attr(int fd,

int baudrate, // B1200 B2400 B4800 B9600 .. B115200

int databit, // 5, 6, 7, 8

const char *stopbit, // "1", "1.5", "2"

char parity, // N(o), O(dd), E(ven)

int vtime=20,

int vmin=2);

private:

void set_baudrate(struct termios *opt, unsigned int baudrate);

void set_data_bit(struct termios *opt, unsigned int databit);

void set_parity(struct termios *opt, char parity);

void set_stopbit(struct termios *opt, const char *stopbit);

void OnReadData();

private:

int mFd;

bool mbExit = false;

OnReadSerialPortDataCallBack mCallBack;

};

// SerialPort.cpp

#include "SerialPort.h"

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <fcntl.h>

#include <unistd.h>

#include <thread>

SerialPort::SerialPort()

{

std::thread t(&SerialPort::ReadData, this);

t.detach();

}

SerialPort::~SerialPort()

{

ClosePort();

mbExit = true;

}

bool SerialPort::OpenPort(const std::string &portName, const OnReadSerialPortDataCallBack &cb)

{

mCallBack = cb;

mFd = open(portName.c_str(), O_RDWR);

if (mFd < 0)

{

printf("open port fail, portName:%sn", portName.c_str());

return false;

}

return true;

}

void SerialPort::ClosePort()

{

if (mFd >= 0)

{

close(mFd);

mFd = -1;

}

}

int SerialPort::set_port_attr(

int fd,

int baudrate, // B1200 B2400 B4800 B9600 .. B115200

int databit, // 5, 6, 7, 8

const char *stopbit, // "1", "1.5", "2"

char parity, // N(o), O(dd), E(ven)

int vtime, // // 等待数据时间(10秒的倍数),每个单位是0.1秒 若20就是2秒

int vmin) // // 最少可读数据,非规范模式读取时的最小字符数,设为0则为非阻塞,如果设为其它值则阻塞,

// 直到读到到对应的数据,就像一个阀值一样,比如设为8,如果只接收到3个数据,那么它是不会返回的,只有凑齐8个数据后一齐才READ返回,阻塞在那儿

{

struct termios opt; //配置串口的属性定义在结构体struct termios中

tcgetattr(mFd, &opt); //获取终端控制属性

//设置波特率

set_baudrate(&opt, baudrate);

opt.c_cflag |= CLOCAL | CREAD; /* | CRTSCTS */

//设置数据位

set_data_bit(&opt, databit);

//设置校验位

set_parity(&opt, parity);

//设置停止位

set_stopbit(&opt, stopbit);

//其它设置

opt.c_oflag = 0;

opt.c_lflag |= 0;

opt.c_oflag &= ~OPOST;

opt.c_cc[VTIME] = vtime;

opt.c_cc[VMIN] = vmin;

/* TCIFLUSH 刷清输入队列

TCOFLUSH 刷清输出队列

TCIOFLUSH 刷清输入、输出队列 */

tcflush(fd, TCIOFLUSH); // //刷串口清缓存

return (tcsetattr(mFd, TCSANOW, &opt)); // //设置终端控制属性,TCSANOW:不等数据传输完毕就立即改变属性

}

/**

* @brief set_baudrate 设置波特率

* @param opt

* @param baudrate

*/

void SerialPort::set_baudrate(struct termios *opt, unsigned int baudrate)

{

cfsetispeed(opt, baudrate);

cfsetospeed(opt, baudrate);

}

/**

* @brief set_data_bit 设置数据位

* @param opt

* @param databit

*/

void SerialPort::set_data_bit(struct termios *opt, unsigned int databit)

{

opt->c_cflag &= ~CSIZE;

switch (databit) {

case 8:

opt->c_cflag |= CS8;

break;

case 7:

opt->c_cflag |= CS7;

break;

case 6:

opt->c_cflag |= CS6;

break;

case 5:

opt->c_cflag |= CS5;

break;

default:

opt->c_cflag |= CS8;

break;

}

}

/**

* @brief set_parity 设置奇偶校验位

* @param opt

* @param parity

*/

void SerialPort::set_parity(struct termios *opt, char parity)

{

switch (parity) {

case 'N': /* no parity check */

opt->c_cflag &= ~PARENB;

break;

case 'E': /* even */

opt->c_cflag |= PARENB;

opt->c_cflag &= ~PARODD;

break;

case 'O': /* odd */

opt->c_cflag |= PARENB;

opt->c_cflag |= ~PARODD;

break;

default: /* no parity check */

opt->c_cflag &= ~PARENB;

break;

}

}

/**

* @brief set_stopbit 设置停止位

* @param opt

* @param stopbit

*/

void SerialPort::set_stopbit(struct termios *opt, const char *stopbit)

{

if (0 == strcmp(stopbit, "1")) {

opt->c_cflag &= ~CSTOPB; /* 1 stop bit */

}

else if (0 == strcmp(stopbit, "1")) {

opt->c_cflag &= ~CSTOPB; /* 1.5 stop bit */

}

else if (0 == strcmp(stopbit, "2")) {

opt->c_cflag |= CSTOPB; /* 2 stop bits */

}

else {

opt->c_cflag &= ~CSTOPB; /* 1 stop bit */

}

}

int SerialPort::WriteData(const char* buf, int len)

{

if (mFd < 0) return -1;

int totalLen = len;

int wtLen = 0;

while (totalLen > 0)

{

int n = write(mFd, buf+ wtLen, totalLen);

totalLen -= n;

wtLen += n;

}

//fflush(&mFd);

return wtLen;

}

void SerialPort::OnReadData()

{

uint8_t dataBuf[1024 * 500] = { 0 };

while (!mbExit)

{

int len = read(mFd, dataBuf, sizeof(dataBuf));

if (len > 0)

{

if (!mCallBack)

{

std::vector<uint8_t> vec(dataBuf, dataBuf + len);

mCallBack(vec);

}

}

}

}

最后

以上就是壮观马里奥为你收集整理的Linux下串口信息的读取的全部内容,希望文章能够帮你解决Linux下串口信息的读取所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部