首先是基于串口助手写的文章,移步此篇,是在这个基础上写的:
基于QT的串口通信助手(MSVC2015+QT5.8)
http://blog.csdn.net/qq_34071268/article/details/79540823
【目标】
能够将GPS采集到的数据通过NMEA协议传输到QT上位机,并实时显示到图片上
参考博客
(1)基于Qt-读取GPS数据(主要参考的gpsPrase的函数)
http://blog.csdn.net/zhang1988pan/article/details/70240037
(2)QT下GPS数据读取与处理!!!(写的不错,没参考)
http://blog.csdn.net/kuailexiaochuan/article/details/45642031
(3)GPS数据格式解析(写的不错,值得参考)
http://blog.csdn.net/u013232740/article/details/45029245
由于只是测试,我采用自发自收的方法进行测试:测试指令如下:
$GNRMC,064401.65,A,3110.4706987,N,12123.2653375,E,0.604,243.2,300713,0.0,W,A*3E
【2018年1月22日星期一 调试记录】
但是通过QDebug出现了错误,如下图所示,发现并不能一直,持续,连续的接收数据,而是分为了五段,第一段有数据,然后空数据,在有数据。并且数据不能通过QT自带的方法进行数据访问!
“$GNRMC,064401.65,A,3110.4706987,”
“”
“N,12123.2653375,E,0.604,243.2,30”
“”
“0713,0.0,W,A*3E”
“”
【失败方案一】
我个人在调试中,使用了多种方法均无法访问
(1)right(),left(),mid()函数 indexOf()函数进行访问->无法访问
(2)使用at()函数可以获取一个指定位置的字符->无法访问
(3)可以用contains()函数来判断该字符串是或否包含一个指定的字符或者字符串。可以使用counts()来获得字符串中一个字符或者子字符串中出现的次数。->无法访问
(4)使用startsWith()和endWith()函数可以判断字符串是以一个字符或者字符串开始或者结束->无法访问
(5)对于两个字符串的比较,可以使用“>”“<=”等操作符,也可以使用compare()函数->无法访问
【失败方案二】
我又尝试了优化方法均不好使“”
(1)GPSBuffer = GPSBuffer.simplified();
(2)QString s = GPSBuffer;
s = s.trimmed(); //不好使
strList = s.split(“\t”);//不好使
strList = s.split(“\n”);//不好使
strList = s.split(“\n”);
QString myStr = strList.join(“\t”);不好使
【2018年1月23日星期二 调试记录】
【失败方案三】
QList gpsByteArrays = GPSBuffer.split(',');
qDebug()<'\n');
int count = line.count('\n');
QByteArray str = gpsByteArrays.at(count-1);
QListgpsByteArrays1 = str.split(',');
输出情况:
-------------------------------------------------------------------------
("$GNGGA", "021830.39", "2303.7670", "N", "113")
("")
("23.9932", "E", "1", "03", "12.7", "14.7", "M", "-7.8", "")
("")
("M", "", "*60")
("")
最后参考变量,代码写的非常烂,但是数据上能显示这些:
void MainWindow::readyReadSlot()
{
static QByteArray allData; //静态变量!!在串口只发送一半的时候用来累加数据
QByteArray dataTemp; //每次读到的数据,可能只是部分的,大多数情况下是正确的,大约1/5会出错
while (!m_reader.atEnd())
{
QByteArray dataTemp = m_reader.readAll(); //因为串口是不稳定的,也许读到的是部分数据而 //已,但也可能是全部数据
if( dataTemp.data()[dataTemp.length() - 1] == '\n'){ //当临时数据最后一位是'~',代表一 //条数据读完了
allData += dataTemp; //总数据加上临时数据
allData.resize(allData.size() - 1); //删除结尾的~符号
//qCritical() << allData; //这时候allData将是你要的数据
this->ui->lineEdit->setText(allData);
allData.clear(); //清除数据!!!!!
}
else{ //当最后一位数据不是'~',即未读完
allData += dataTemp; //每次累加这部分数据,因为可能没发完
}
}
}
【2018年1月24日 星期三 停止调整代码,查看论坛,可看可不看】
【问题描述】
串口助手读取GPS数据发生错乱,我在输入一系列的数字。
GNRMC,064401.65,A,3110.4706987,N,12123.2653375,E,0.604,243.2,300713,0.0,W,A∗3E实际接收到的是:变量QbyteArrayBuffer接收到的数据是:“ G N R M C , 064401.65 , A , 3110.4706987 , N , 12123.2653375 , E , 0.604 , 243.2 , 300713 , 0.0 , W , A ∗ 3 E 实 际 接 收 到 的 是 : 变 量 Q b y t e A r r a y B u f f e r 接 收 到 的 数 据 是 : “ GNRMC,064401.65,A,3110.4706987,”
“”
“N,12123.2653375,E,0.604,243.2,30”
“”
“0713,0.0,W,A*3E”
“”
我对此非常不理解,尝试了字符串.simplifid 等其他方法,字符串是无法合并的。通过测试字符串.size,然后QDebug输出,得到输出 32 0 32 0 6 说明代码中出现了多个字符串。若继续调用,只有”$GNRMC,064401.65,A,3110.4706987,”这个第一段的数据能够被我调用,后面的我无法调用。
(1)QQ群人员:
路人甲1号(天津-宁):在群里问了半天,唯一一个回答比较系统的
你得先收全整个数据帧,gps数据应该是以\n结尾,串口接收是一个长期过程,所以绝对不能用临时变量。临时变量只适用于直接从串口readall时。一个成员变量做recvbuffer,每次readall后的数据都加进去,每次read后都要判断有没有\n,如果有,说明现在recvbuffer中有至少一个完整的gps数据帧。对recvbuffer进行split(‘\n’)。得到list的最后一个元素直接赋值给recvbuff。list中其他元素就是完整的gps帧,可能不只一个。有了完整帧,再来说怎么处理问题。
(2)其他人:
你在类中定义一个QByteArrary,每次触发接收到数据的事件后,readall ,把新接收的数append到arrary 中,然后数逗号,满足要求,则处理,然后把arrary clear,如果不满足要求,不处理,继续等下一个事件,然后添加进arrary。
【我按方式进行了一定的尝试,但是没有成功】
其他人:
它发送数据时应该是分成了多次发送,接收一次就输出一个字符串。我决定应该先设置一个全局变量,接收一次就合并一次字符串,最后再输出。
(3)贴吧:目前唯一找到的一个跟我出现类似状况,并且进入深入讨论的一个帖子:
http://tieba.baidu.com/p/3699753033
Qt5–串口类Qserialport接收及发送数据不完整问题
(1)但是我发现readyRead信号不是每接收到一个字节就发出的,而是连续的一串数据或是几个数据之后。这就造成了数据的不完整,,咳 不知道如何完美解决此问题
(2)我查看了网友的方法:连续读取到一个字符串或者byte类型缓冲区中,读取串口一般不能一次读完,都要分几次,还不如在事件中把数据加到缓冲区,然后触发另一段代码从缓冲区里检查是否存在一个完整的数据帧,先在缓冲区中查找第一个帧头部,如果找到,检查后面的数据够了没有,如果够了就是有一个完整数据帧,把这个帧从缓冲整个取出。
(3)发送数据比较简单,只需要将构造好的数据用Write()方法发送出去即可。
接收数据则比较复杂,通讯是以字节流的形式到达的,通过调用一次Read()方法并不能确保所读取的数据就是完整一桢。因此需要将每次读取的数据整合在一起,对整合后的数据进行分析,按照定义的桢格式,通过桢头和桢尾,将桢信息从字节流中抽取出来,这样才能获取有意义的信息。
打开win_qextserialport类,发现有这么一个功能函数:qint64 Win_QextSerialPort::bytesAvailable(),这个函数的功能描述是说将 接收队列中等待的字节数 作为return返回值。所以我认为,增加一句 if(bytesAvailable()>10)这样的判断,接收队列中有10个字节了,然后再read()进去
(4)读取数据加了一个前提:if(Myport->bytesAvailable() >=24 ) 但是还是会出现接收数据断层。。咳 。。不知道解决了。。。。求助。。
(5)[解决办法]
1.如果知道包长的话,根据包长度来确认数据接收完
2.另一种方法,给每包加上包头和包尾,根据包头包尾确认包接收完
这种方式最好,加一个超时机制,以防数据只收到一部分通信中断,收包不全的情况,应通过超时机制将这些包丢弃或做特殊处理
不太会编程去实现这些解决方法。。。。比如我分两次接收的数据怎么合并了?
(6)你好,楼主你解决这个问题了吗?
我想到一个方法,就是
QByteArray ReadData;
while(my_serialport->waitForReadyRead(50)) //一直循环读取,知道读取完后返回false
{
ReadData+=my_serialport->readAll();
}
一直读写,不过还是用到
QObject::disconnect(my_serialport,SIGNAL(readyRead()),this,SLOT(readMyCom()));
(7)我现在也遇到这个问题,我先用的是在槽里,弄一个QThread类的 usleep 延时读取,好让数据发送完毕 在全部读取。这样可以实现。不过还是 按照最后你说的那个方法实现比较好,一帧检测,楼主还记不得或者有没有代码 给我参考下子。
【后来得到的一个bug代码版本一】
【串口接收函数】
QByteArray temp=myCom->readAll();
byteArray.append(temp);
if(!temp.isEmpty()&&byteArray.length()>=65)
{
//qDebug()<textBrowser->insertPlainText(temp);
}
temp.clear();
byteArray.clear();
【bug出现情况】
数据改变无法更新,因为最后缓存机制还是会出现两段相同的代码。而更改数据时,后面第二次的缓存数据可更改,但是数据无法提取,跟上述写的很像。
【bug出现情况二,同一一样的错误】
if(!isHexRead)
{
QByteArray temp;
static QString str;
QByteArray tempData;
temp = temp.append(myCom->readAll()) ;
str+= temp;
if(!str.isEmpty()&&str.length()>64)
{
ui->textBrowser->insertPlainText(str);
qDebug()<
void MainWindow::readMycom()//读串口函数
{
//QByteArray temp = myCom->readAll();
//读取串口的数据显示在窗口的文本浏览器
//ui->textBrowser->insertPlainText(temp);
//将串口的数据显示在窗口文本浏览器中
//$GNRMC,050912.00,A,2309.927161,N,11325.858832,E,0.1,,161211,,,A*6E
int isHexRead=ui->isHexRead->isChecked();
static QByteArray byteArray;
if(!isHexRead)
{
if(myCom->bytesAvailable()>=66)
{
QByteArray temp = myCom->readAll();
if(!temp.isEmpty())
{
qDebug()<;
ui->textBrowser->insertPlainText(temp);
}
}
}