天天看點

Linux之序列槽接收響應試驗問題來源

問題來源

儀表作為從機時,需要分析儀表的響應速度。但發現采用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

Linux之序列槽接收響應試驗問題來源

電腦發送内容: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"方式和是相同的。

繼續閱讀