• linux下串口多线程通信 ,多串口收发数据错乱问题解决办法


    最近在写AM335x平台的串口测试工具,最开始的时候写的第一版本,测试一直很ok,但是存在一些缺陷,于是就想改进一下,没想到后面在新的板子测试,竟然发现了以个很致命的问题,在旧系统旧内核测试一切正常,在新系统的情况下,系统16路串口测试,am335x自带的4路总是出现丢包的问题,其他扩展出来的16路没有任何问题,于是折腾了好久。

    总算搞定。

    我的板子系统自带4路,经过spi扩展出来12路,总的16路,首先是串口配置,一般有两种情况下的配置,一种是使用默认的参数直接配置即可,一种就是根据自己的需要重新配置。

    首先定义termios结构体

     static  struct termios termold[17],termnew[17];

    使用系统默认参数配置:

    fd[i]=open(port[i],O_RDWR) ;     //打开串口
    tcgetattr(fd[i],&termold[i]);          //获得默认串口配置参数
    tcgetattr(fd[i],&termnew[i]);
    cfmakeraw(&termnew[i]);          //使用cfmakeraw 配置
    cfsetspeed(&termnew[i],B115200); //{115200,460800,921600}           //设置波特率
    tcsetattr(fd[i],TCSANOW,&termnew[i]);                                                //立即生效

    这里直接使用cfmakeraw,将串口设置为原始模式

    这个在新系统是不可用的,不知道什么原因,这样接收就会丢包,可能被内核优化了吧。

     重新配置串口参数: 配置为阻塞模式

    if(tcgetattr(fd[i], &termold[i]) != 0)
    {
    perror("SetupSerial 1");
    return ;
    }
    bzero(&termnew[i], sizeof(termnew[i]));
    termnew[i].c_iflag &= ~(ICRNL|IGNCR) ;
    termnew[i].c_cflag |= CLOCAL | CREAD; //CLOCAL:忽略modem控制线 CREAD:打开接受者
    termnew[i].c_cflag &= ~CSIZE;
    termnew[i].c_cflag |= CS8;
    termnew[i].c_cflag &= ~PARENB;
    cfsetispeed(&termnew[i], B115200);
    cfsetospeed(&termnew[i], B115200);
    termnew[i].c_cflag &= ~CSTOPB;
    termnew[i].c_cc[VTIME] = 20; //VTIME:非cannoical模式读时的延时,以十分之一秒位单位
    termnew[i].c_cc[VMIN] = LENGHTH ; //VMIN:非canonical模式读到最小字符数
    tcflush(fd[i],TCIFLUSH); // 改变在所有写入 fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃。
    if((tcsetattr(fd[i],TCSANOW,&termnew[i]))!=0) //TCSANOW:改变立即发生
    {
    perror("com set error");
    return ;
    }
    perror(" set done!");

    关于这两种的配置,网上很多,直接搜索 linux串口通信配置  就会有很多,这里不阐述。

    因为我这里要测试16路,所以用数组保存fd  termnew  ,配置好评后,如果要测试多路,基本都是创建线程实现。

    在这里我是使用双向收发,把 读取设置为阻塞,就可以收发,例如:

    串口1发送到串口2  串口2收到后会发给串口1  这样循环 

    我是使用线程实现,开始的时候也总是出问题,就是系统自带的串口1和2   11和12,总是丢包,或者接收顺序不对数据感觉呗截取

    但是单独开窗口,telnet登录各自单独才是,开8个窗口测试16路,都没有问题

    所以我想到不使用线程管理,而是每一路开自己的进程管理,这样也没有问题,就是使用多线程的时候就出现问题,经过一番折腾,总算解决多线程通信的问题

    一开始我在定义数据的时候使用static来修饰,到这这样就出现了问题,而且只是系统自带的串口出现问题,其他的都正常 

    加static修饰

     运行结果出错:

     去掉static直接ok,

    线程代码如下:

    void* read_thread(void* arg)
    {
    char write_txbuf[LENGHTH] = DATE_STRING;
    char read_rxbuf[LENGHTH]={0} ;
    char checkbuf[LENGHTH] = DATE_STRING;;
    //printf("线程开始进入 %d ",paramer_in) ;
    while(1){
    //clear rxdate buf ===read===
    memset(read_rxbuf,0,sizeof(read_rxbuf));
    retlen[(int)arg]= read(fd[(int)arg],read_rxbuf,sizeof(read_rxbuf));
    if(strcmp(checkbuf, read_rxbuf)==0){
    rxtotal[(int)arg]+=retlen[(int)arg];
    }else{
    faillen[(int)arg]+=retlen[(int)arg] ;
    tcflush(fd[(int)arg],TCIFLUSH); //如果接收失败 刷新缓冲 继续接收
    }
    //===write===
    txlen[(int)arg]= write(fd[(int)arg],write_txbuf,sizeof(write_txbuf));
    txtotal[(int)arg]+=txlen[(int)arg] ;

    }
    }
    void* write_thread(void* arg)
    {
    char write_txbuf[LENGHTH] = DATE_STRING;
    char read_rxbuf[LENGHTH]={0} ;
    char checkbuf[LENGHTH] = DATE_STRING;;
    //printf("线程开始进入 %d ",paramer_in) ;
    while(1){
    txlen[(int)arg] = write(fd[(int)arg],write_txbuf,sizeof(write_txbuf)) ;

    memset(read_rxbuf,0,sizeof(read_rxbuf)); //clear rxdate buf
    retlen[(int)arg] = read(fd[(int)arg],read_rxbuf,sizeof(read_rxbuf)) ; //send after receive
    if(strcmp(checkbuf, read_rxbuf)==0){
    rxtotal[(int)arg]+=retlen[(int)arg];
    //printf(" ===rev:%s send:%s len:%d=== ",read_rxbuf, write_txbuf, retlen[paramer_in]) ;
    }else{
    faillen[(int)arg]+=retlen[(int)arg] ;
    tcflush(fd[(int)arg],TCIFLUSH); //如果接收失败 刷新缓冲 继续接收
    }
    //因为read会有阻塞 所以等接收到后再加 避免发送回比接收多
    txtotal[(int)arg]+=txlen[(int)arg] ;

    }
    }

     运行结果:

     总结:linux串口通信多线程,新版的内核相对于旧版的,发送速度明显提升,而且芯片自带的串口比经过扩展出来的块很多倍,也可能是发送太快,我16线程频繁调用,导致分配 内存不过来,或者给发送结束后增加100ms以上的延时,所有串口速度差不多的时候,也是所有的都是正常的,所有折腾了很久。  最后去掉static直接ok  所有linux多线程,要谨慎使用static  

  • 相关阅读:
    て和で用法的总结
    假如程序员上热搜是什么样的?网友:毫无违和感!
    一年精通,三年熟悉,五年了解,十年用过!C++真的这么难吗?
    新手上路,“hello word”其实是在告诉计算机又有菜鸟来了!
    从原理到方法,一步到位,教你如何应对C语言内存泄露!
    冰冷的英语字母,枯燥的编程教程,果断选择了放弃!真的吗?
    只有了解程序员的黑话,和他们打成一片获得buff加成,产品才能尽早上线!
    C语言编程小游戏「石头剪刀布」!源码分享~
    一行代码卖出570美元,什么样的代码能这么值钱?带你揭秘天价代码的内幕!
    源码解剖HashMap
  • 原文地址:https://www.cnblogs.com/ChenChangXiong/p/10977813.html
Copyright © 2020-2023  润新知