Linux之串口接收响应试验

9 篇文章 0 订阅
4 篇文章 0 订阅

问题来源

仪表作为从机时,需要分析仪表的响应速度。但发现采用linux或windows开发时发现串口响应较慢。在网上没有查到相关的资料,于是在手上的linux产品上进行试验。(iMAX6Q)

试验一 、采用linux文件读写方式测试响应速度

测试代码
#include “testfuncrun.h”
#ifdef D38_board
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <termios.h>
#include <linux/serial.h>

#define PortName “ttymxc2”
#endif
#include “SerialTool/SerialTool.h”

TestFuncRun::TestFuncRun()
{
m_toStop = false;
}

TestFuncRun::~TestFuncRun()
{
qDebug()<<"~TestFuncRun()";
m_toStop = true;
wait();
}

void TestFuncRun::stop()
{
m_toStop = true;
}

#ifdef D38_board
int rs485_enable(int fd,int enable)
{
struct serial_rs485 rs485conf;
int res;
res=ioctl(fd,TIOCGRS485,&rs485conf);
if(res<0){
printf(“rs485 config read fail \n”);
return res;
}

if(enable){
    rs485conf.flags |=SER_RS485_ENABLED;
    rs485conf.flags |=SER_RS485_RTS_AFTER_SEND;
}
rs485conf.delay_rts_before_send=0x0004;
res=ioctl(fd,TIOCSRS485,&rs485conf);
if(res<0){
    printf("rs485 confing set fail\n");
}
return res;

}
int uartdev_init(int fd)
{
struct termios newtty,oldtty;
if(tcgetattr(fd,&oldtty)!=0){
printf(“tcgetattr fail \n”);
return -1;
}
bzero(&newtty,sizeof(newtty));
newtty.c_cflag|=(CLOCAL|CREAD);
newtty.c_cflag&=~CSIZE;
#if 0
switch(bit){
case 7:
newtty.c_cflag |=CS7;
break;
case 8:
newtty.c_cflag |=CS8;
break;
default:
newtty.c_cflag |=CS8;
}
#endif

newtty.c_cflag |=CS8;

newtty.c_cflag &=~PARENB;

cfsetispeed(&newtty,B19200);
cfsetospeed(&newtty,B19200);

newtty.c_cflag &=~CSTOPB;

// if(havecrtscts==1){
// newtty.c_cflag |=CRTSCTS;
// }

    newtty.c_cc[VTIME] = 0;
    newtty.c_cc[VMIN]  = 0;
tcflush(fd ,TCIFLUSH);

if((tcsetattr( fd, TCSANOW,&newtty))!=0)
{
    perror("com set error");
    return -1;
}
    return 0;

}

void TestFuncRun::run()
{
//QSerialPort serial;
int count=0;
bool serialOK = false;
int ret;
//serialOK = SerialTool::SerialOpen(&serial,m_PortName,“9600”,“8”,“无校验”,“1”);
// qDebug()<<“serialOK = “<<serialOK;
int gfd = open(”/dev/ttymxc2”,O_RDWR|O_NOCTTY);

ret = uartdev_init(gfd);
ret = rs485_enable(gfd,1);
if(ret != 0){
    serialOK = false;;
}
else
{
    serialOK = true;
}
qDebug()<<"serialOK = "<<serialOK;
char readbuff[11];
char cmpbuff[11];
char cmpbuff2[10]={'a','b','c','d','e','a','b','c','d','e'};
memset(cmpbuff,0,11);
while(m_toStop == false)
{
   if(serialOK == false)
   {
        msleep(1000);
   }
   else
   {
       memset(readbuff,0,11);
       //printf("uart readloop\n");
       ret=read(gfd,readbuff,10);
       readbuff[10]=0;
       if(ret !=0)
       {
        // printf("read buff:%s\n",readbuff);
       }
       if(strcmp(readbuff,"abcdeabcde")!=0 &&strcmp(readbuff,cmpbuff)!=0){
           printf("!!!!!!!!wrong val\n");
           printf("read buff:%s\n",readbuff);
       }
       //usleep(10*1000);
       if(strcmp(readbuff,"abcdeabcde")==0){
           write(gfd,"recive abcde",12);
       }
       else
       {
         if(ret !=0)
         {
             write(gfd,"recive fail",12);
         }
       }
   }
   //qDebug()<<"count = "<<count;
   count++;
   if(count>999999)
   {
       count = 0;
   }




}
if(serialOK == true)
{
  close(gfd);
}
qDebug()<<"end of run()";

}

#else
void TestFuncRun::run()
{
int count=0;

while(m_toStop == false)
{
   qDebug()<<"count = "<<count;
   count++;
   if(count>999999)
   {
       count = 0;
   }


   msleep(1000);



}
qDebug()<<"end of run()";

}
#endif

在这里插入图片描述

电脑发送内容:abcdeabcde(发送个数10)
波特率为115200时,响应时间为3ms
波特率为19200时,响应时间为20ms
波特率为9600时,响应时间为40ms
波特率为2400时,响应时间为160ms

电脑发送内容:abcdeabcdeabcdeabcde(发送个数20)
波特率为115200时,响应时间为3ms–
波特率为19200时,响应时间为20ms

电脑发送内容:abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde(发送个数100)
波特率为115200时,响应时间为3ms
波特率为9600时,响应时间为40ms

小结:linux串口就算收到数据,但反馈到应用层还需一定的时间,他的反映时间原理猜想如下:
当收到数据若n时间没有再收到数据,则向应用层反馈有数据收到。
时间n与接收字节数无关.而只与波特率有关.
注:偶尔也会收到一半就提前响应。比如电脑向仪表连续发送100个字节,结果仪表接收了70个字节就响应了有字节收到了。

第二项试验,验证Qt的串口函数是否有影响(serial.read(100))

void TestFuncRun::run()
{
QSerialPort serial;
int count=0;
bool serialOK = false;
int ret;
serialOK = SerialTool::SerialOpen(&serial,"/dev/ttymxc2",“9600”,“8”,“无校验”,“1”);
qDebug()<<"serialOK = "<<serialOK;
QByteArray readArr;
while(m_toStop == false)
{
if(serialOK == false)
{
msleep(1000);
}
else
{
//printf(“uart readloop\n”);
readArr.clear();
readArr = serial.read(100);
qApp->processEvents();
if(readArr.count() !=0)
{
serial.clearError();
serial.write(readArr);
}
}
//qDebug()<<"count = "<<count;
count++;
if(count>999999)
{
count = 0;
}

}
if(serialOK == true)
{
 serial.close();
}
qDebug()<<"end of run()";

}

测试情况:
电脑发送内容:0123456789(发送个数10)
波特率为9600时,响应时间为40ms

电脑发送内容:0123456789。。(发送个数100)
波特率为9600时,响应时间为40ms

电脑发送内容:0123456789。。(发送个数100)
波特率为115200时,响应时间为3ms

1、同时没有出现过电脑连续发送100个字节,结果70个就反馈有数据的情况;
2、注:readArr = serial.read(100);虽说写了最大100个字节,而实际是全部接收,比如电脑连接发送200个字节给仪表,此时readArr就是接收了200个字节.
3、物理串口接收完毕至应用层响应时间完全同liunx 原始串口调用的响应时间

第三项试验,验证Qt的串口函数是否有影响(waitForReadyRead)

void TestFuncRun::run()
{
QSerialPort serial;
int count=0;
bool serialOK = false;
int ret;
serialOK = SerialTool::SerialOpen(&serial,"/dev/ttymxc2",“115200”,“8”,“无校验”,“1”);
qDebug()<<"serialOK = "<<serialOK;
QByteArray readArr;
while(m_toStop == false)
{
if(serialOK == false)
{
msleep(1000);
}
else
{
//printf(“uart readloop\n”);
readArr.clear();
if(serial.waitForReadyRead(200)) {
qApp->processEvents();
readArr = serial.readAll();
if(readArr.count() !=0)
{
serial.clearError();
serial.write(readArr);
}

       }

   }
   //qDebug()<<"count = "<<count;
   count++;
   if(count>999999)
   {
       count = 0;
   }




}
if(serialOK == true)
{
 serial.close();
}
qDebug()<<"end of run()";

}

测试:
电脑发送内容:0123456789。。(发送个数100)
波特率为9600时,响应时间为40ms

电脑发送内容:0123456789。。(发送个数100)
波特率为115200时,响应时间为3ms

电脑发送内容:0123456789。。(发送个数200)
波特率为115200时,响应时间为3ms

1、同时没有出现过电脑连续发送100个字节,结果70个就反馈有数据的情况;
2、物理串口接收完毕至应用层响应时间完全同liunx 原始串口调用的响应时间

实验四、设置接收缓冲,看是否响应有无影响

void TestFuncRun::run()
{
QSerialPort serial;
int count=0;
bool serialOK = false;
int ret;
serialOK = SerialTool::SerialOpen(&serial,"/dev/ttymxc2",“9600”,“8”,“无校验”,“1”);
qDebug()<<"serialOK = "<<serialOK;
QByteArray readArr;
serial.setReadBufferSize(50);
while(m_toStop == false)
{
if(serialOK == false)
{
msleep(1000);
}
else
{
//printf(“uart readloop\n”);
readArr.clear();
if(serial.waitForReadyRead(200)) {
qApp->processEvents();
readArr = serial.readAll();
if(readArr.count() !=0)
{
serial.clearError();
serial.write(readArr);
}

       }

   }
   //qDebug()<<"count = "<<count;
   count++;
   if(count>999999)
   {
       count = 0;
   }




}
if(serialOK == true)
{
 serial.close();
}
qDebug()<<"end of run()";

}

测试:
电脑发送内容:0123456789。。(发送个数10)
波特率为9600时,响应时间为40ms

电脑发送内容:0123456789。。(发送个数40)
波特率为9600时,响应时间为40ms

电脑发送内容:0123456789。。(发送个数50)
波特率为9600时,响应时间为40ms

电脑发送内容:0123456789。。(发送个数60)
波特率为9600时,响应时间为40ms,且60个数据都接收正常。

小结:(serial.setReadBufferSize(50);)设置接收缓存没有起到缩短串口响应的作用,当电脑向仪表连续发送60个字节时,仪表也是能正常接收,即说明这个设置缓存没有什么作用.

总结:
linux物理接收完数据(内核)至应用层响应(指示有数据接收)的时间只受波特率有关。(与接收缓存大小、调用Qt函数还是底层的文件方式都 没有关系)。------这一点不如单片机的实时性高。
注:以上结论属在imax6Q的测试结果.

1、经咨询供应商后的处理方法:通过更改驱动中寄存器的值,最多可以减少一半的时间,如原9600bps下由40ms变为20ms。同时供应商说liunx实时性差,很多设备采用外扩个单片机来解决这个问题。建议用集成了M4核的系统,由于项目时间问题,此问题暂时放下。
2、Qt5.6-linux串口采用调用时,存在内核串口已有数据,但应用层仍没有收到 数据的,导致两个指令包一起接收的情况。若采用Qt5.9-win则不存在这个问题。
解决方法是采用linux的“open”方式操作串口。缺点是:校验方式上没有搞定mark和space。由此可见Qt在串口处理上还需改进,另外延时问题上经测试。这个延时时间"open"方式和是相同的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值