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

查看:59
本文介绍了在 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.
");
    exit(EXIT_FAILURE);
}
else
 {

    if(tcgetattr(fd, &tty_attributes) == -1)
    {
        perror("tcgetattr termios function error.
");
        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
");
        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
");
    }
}

我有一个 gps 模块与 UART 连接,当我使用 minicom 检查时,我得到了全帧,但是当我通过 uart 接收(使用此代码)时,我只得到前 16 个字节.谁能指出我的错误.?这里波特是 9600 ,帧是 64 字节,大小是 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 文件

My main.c file

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
");
  }
  else
  {

     printf("port is open for communication:
");
     readb = frame_read(fd);
     for (i=0;i<=34;i++)
      {
          data[i] = *(readb +j);
         printf("the data is %x
",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.

还更新了我在终端和程序上获取的框架图片.可能会更清楚.

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 文本,分隔为以回车和换行结尾的行,但您的程序使用非规范模式而不是规范模式来读取.minicom 输出证实了@pbn 的假设.

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.
");
        return (-2);
    }
    if (tcgetattr(fd, &tty_attributes) == -1) {
        perror("tcgetattr termios function error.
");
        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.
");
        return (-4);
    }
    return fd;
}

每个系统调用读取一行的修改例程:

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
");
        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);
}

修改后的 ma​​in() 例程永远循环:

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
");
        exit (EXIT_FAILURE);
    }
    printf("port is open for communication:
");
    do {
        readb = frame_read(fd);
        while (*readb > 0)
            printf("the data is 0x%x
", *readb++);
        printf("The line is: %s", frame);
    } while (1);  /* loop for another line */
    close(fd);
}

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

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