在C中使用linux串行端口,无法获取完整数据 [英] Working with linux serial port in C, Not able to get full data

查看:80
本文介绍了在C中使用linux串行端口,无法获取完整数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用用C编写的Linux串行端口.这是我的UART设置

I am working with Linux Serial port written in C. Below is my UART settings

 int fd;
 struct termios tty_attributes;
 fd = open(comport, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK );

if(fd < 0)
{
    perror("open comport error.\n");
    exit(EXIT_FAILURE);
}
else
 {

    if(tcgetattr(fd, &tty_attributes) == -1)
    {
        perror("tcgetattr termios function error.\n");
        exit(EXIT_FAILURE);
    }

    tty_attributes.c_lflag = 0;
    tty_attributes.c_oflag = 0;
    tty_attributes.c_iflag = 0;
    tty_attributes.c_cflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
    tty_attributes.c_cflag |= CS8;
    tty_attributes.c_cflag |= CLOCAL;
    tty_attributes.c_cflag &= ~CREAD;
    tty_attributes.c_oflag &= ~OPOST;
    tty_attributes.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
    tty_attributes.c_cc[VMIN] = SIZE_STR_FRAME;
    cfsetospeed(&tty_attributes, BAUDRATE);       //setting communication speed and other attributes
    cfsetispeed(&tty_attributes, BAUDRATE);
    tcflush(fd, TCIOFLUSH);
    tcsetattr(fd, TCSANOW, &tty_attributes);     //change immediately
    return fd;
}

}

下面是我读取框架的代码

And below is my code for Reading the frame

char* frame_read(int fd)
{
    char *ret = NULL;
    int read_ret_val;
    struct timeval time_val;
    if (fd < 0)
    {
        printf("Before read over comm channel, channel must be initialize\n");
        exit(EXIT_FAILURE);
    }
    memset(frame, 0, SIZE);
    fd_set rfds;        //read file discriptors
    int return_val;
    FD_SET(fd, &rfds);

    setReceiveMode(fd, TRUE);
    tcflush(fd, TCIFLUSH);
    tcflush(fd, TCOFLUSH);    //flush previous values
    return_val = select((fd) + 1, &rfds, NULL, NULL, &time_val);
    if (return_val == -1)
    {
        perror("select");
        exit(EXIT_FAILURE);
    }

    else if (return_val)
    {
        usleep(100 * 1000);
        read_ret_val = read(fd, frame, SIZE);
        if (read_ret_val < 0)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }
        ret = frame;
        //printf("inside else if of read\n");
    }
}

我有一个与UART连接的gps模块,当我用minicom进行检查时,我会得到全帧显示,但是当我通过uart接收到(使用此代码)时,我只会得到前16个字节. 谁能指出我的错误? 这里的波特是9600,帧是64个字节,SIZE是64个字节.,我占用的缓冲区也是64个字节.如果有格式错误,请原谅我.

I have one gps module is connected with the UART and when i check with minicom I am getting full frame but when i receive over uart(using this code) I am getting first 16 bytes only. Can anyone point my mistake.? Here baud is 9600 , frame is of 64 bytes and SIZE is of 64 bytes.,buffer i took is also 64 bytes. Please forgive me for formating errors if any.

我的main.c文件

int main(int argc, char *argv[])
{
  int i=0,j=0;
  char *readb;
  unsigned char data[34];
  static int fd = -1;
  struct struct_base_gps *gps;
  int command=0;
  char COMM_PORTNAME[13];
  strcpy( COMM_PORTNAME, argv[1] );// give the first port number for GPS receiving
  if((fd = init_comm_channel(COMM_PORTNAME)) < 0 )
  {
       exit(EXIT_FAILURE);
       printf("port is not opened\n");
  }
  else
  {

     printf("port is open for communication:\n");
     readb = frame_read(fd);
     for (i=0;i<=34;i++)
      {
          data[i] = *(readb +j);
         printf("the data is %x\n",data[i]);
         j++;
     }
  }
  close (fd);

}

对于SIZE是 #定义尺寸64 和框架是 字符框[64];

for SIZE is #define SIZE 64 and frame is char frame[64];

谢谢您的反馈,我已经更新了代码.

Thank you for feedback, I have updated the code.

还更新了我在终端以及程序中获得的Frame图片.可能会清除更多.

Also Updating the Frame pics which I am getting on terminal as well as with program. Might It will clear more.

通过程序从UART接收数据

接收到minicom

推荐答案

您的原始代码有很多问题,导致其仅获取前16个字节" :

Your original code has numerous issues which cause it to "getting first 16 bytes only":

  • 代码(如前所述)仅执行一个 read()系统调用(而不是连续循环以从设备读取数据).

  • The code (as posted) only performs a single read() syscall (rather than continuously loop to read the data from the device).

输入显然是ASCII文本,分隔为以回车和换行符结尾的行,但是您的程序使用非规范模式读取而不是规范模式. @pbn的假设已由 minicom 输出确认.

The input is obviously ASCII text delimited into lines terminated with carriage return and line feed, yet your program uses non-canonical mode to read rather than canonical mode. The assumption by @pbn is confirmed by the minicom output.

您的程序在非阻塞模式而不是阻塞模式下使用串行终端,并诉诸于使用 select() usleep()调用等待数据到达.

Your program uses the serial terminal in non-blocking mode, rather than blocking mode, and resorts to using select() and usleep() calls to wait for the arrival of data.

termios 初始化(除了不符合POSIX)有几个错误,包括对 cflag 成员应用了不正确的 iflag 符号,无法使用〜CSIZE清除字符大小位,并且未启用CREAD.

The termios initialization (besides not being POSIX compliant) has several errors, including improper iflag symbols applied to the cflag member, the character size bits are not cleared with ~CSIZE, and CREAD is not enabled.

您的读取例程在 select()调用之前不必要地刷新(即丢弃)所有已接收但未读取的数据.

Your read routine unnecessarily flushes (i.e. discards) all received but unread data prior to the select() call.

修改后的例程,用于打开和配置串行终端(用于阻止规范模式):

A revised routine for opening and configuring the serial terminal (for blocking canonical mode):

#define BAUDRATE    B9600

int init_comm_channel(char *comport)
{   
    struct termios tty_attributes;
    int fd;

    fd = open(comport, O_RDWR | O_NOCTTY);
    if (fd < 0) {
        perror("open comport error.\n");
        return (-2);
    }
    if (tcgetattr(fd, &tty_attributes) == -1) {
        perror("tcgetattr termios function error.\n");
        return (-3);
    }
    tty_attributes.c_cflag |= CLOCAL | CREAD;
    tty_attributes.c_cflag &= ~CSIZE;
    tty_attributes.c_cflag |= CS8;         /* 8-bit characters */
    tty_attributes.c_cflag &= ~PARENB;     /* no parity bit */
    tty_attributes.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
    tty_attributes.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

    tty_attributes.c_lflag |= ICANON | ISIG;  /* canonical input */
    tty_attributes.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);

    tty_attributes.c_iflag &= ~INPCK;
    tty_attributes.c_iflag |= IGNCR;
    tty_attributes.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
    tty_attributes.c_iflag &= ~(IXON | IXOFF | IXANY);   /* no SW flowcontrol */

    tty_attributes.c_oflag &= ~OPOST;

    cfsetospeed(&tty_attributes, BAUDRATE);       //setting communication speed and other attributes
    cfsetispeed(&tty_attributes, BAUDRATE);
    tcflush(fd, TCIOFLUSH);

    if (tcsetattr(fd, TCSANOW, &tty_attributes) < 0) {
        perror("tcsetattr function error.\n");
        return (-4);
    }
    return fd;
}

修改后的例程,用于读取每个syscall的行:

The revised routine for reading a line per syscall:

#define SIZE    64
unsigned char frame[SIZE];

char *frame_read(int fd)
{
    int read_ret_val;

    if (fd < 0) {
        printf("Before read over comm channel, channel must be initialize\n");
        exit (EXIT_FAILURE);
    }
    read_ret_val = read(fd, frame, SIZE - 1);
    if (read_ret_val < 0) {
        perror("read");
        exit (EXIT_FAILURE);
    }
    frame[read_ret_val] = 0; /* terminate string */
    return (frame);
}

修改后的 main()例程,该例程将永远循环:

A revised main() routine that loops forever:

int main(int argc, char *argv[])
{
    int fd;
    char *readb;
    char com_portname[13] = {0};

    if (argc > 1)
        strcpy(com_portname, argv[1]);  // give the first port number for GPS receiving
    if ((fd = init_comm_channel(com_portname)) < 0) {
        printf("port is not opened\n");
        exit (EXIT_FAILURE);
    }
    printf("port is open for communication:\n");
    do {
        readb = frame_read(fd);
        while (*readb > 0)
            printf("the data is 0x%x\n", *readb++);
        printf("The line is: %s", frame);
    } while (1);  /* loop for another line */
    close(fd);
}

这篇关于在C中使用linux串行端口,无法获取完整数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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