0 背景
项目需求,要用Qt接收惯导数据,数据采用UDP传输,在Qt中提供了QUdpSocket类来进行UDP数据报(datagrams)的发送和接收。这里我们还要了解一个名词Socket,也就是常说的“套接字”。 Socket简单地说,就是一个IP地址加一个port端口。因为我们要传输数据,就要知道往哪个机子上传送,而IP地址确定了一台主机,但是这台机子上可能运行着各种各样的网络程序,我们要往哪个程序中发送呢?这时就要使用一个端口来指定UDP程序。所以说,Socket指明了数据报传输的路径。
为了使惯导数据的接收不影响主页面的响应,创建新线程来不停地读取数据。下面创建一个UDP的接收端程序。新建一个mainwindow工程,在pro文件中添加QT += network,然后执行以下qmake,确保没有问题。新建gnss类,继承QThread,包括gnss.h和gnss.cpp文件。话不多说,直接上代码!
1 gnss.h
#ifndef GNSS_H
#define GNSS_H
#include <QThread>
#include <QtCore>
#include <QObject>
#include <QMutex>
#include <iostream>
#include <QtNetwork>
class GNSS: public QThread
{
public:
Q_OBJECT
public:
GNSS();
void stop();
private slots:
void run();
void processPendingDatagram();
private:
bool stopped;
QMutex m_lock;
QUdpSocket *receiver;
QFile f();
};
#endif // GNSS_H
2 gnss.cpp
#include "gnss.h"
#include <QTimer>
#include <QMutexLocker>
#include "mainwindow.h"
GNSS::GNSS()
{
stopped = false;//标记可以运行
//创建一个QUdpSocket类对象,该类提供了Udp的许多相关操作
receiver = new QUdpSocket(this);
int port =3000;//设置UDP的端口号参数,指定在此端口上监听数据
//此处的bind是个重载函数,连接本机的port端口,采用ShareAddress模式(即允许其它的服务连接到相同的地址和端口,特别是
//用在多客户端监听同一个服务器端口等时特别有效),和ReuseAddressHint模式(重新连接服务器)
int receive = receiver->bind(QHostAddress("195.0.0.230"),port);
qDebug() << "receive: " <<receive << endl;
if(receive == 0)
{
qDebug() << "UDP Connected Succeed ! " << endl;
}
else
{
qDebug() << "UDP Connected Faild ! " << endl;
}
}
void GNSS::stop()
{
QMutexLocker locker(&m_lock);
stopped = true;
receiver->close();
delete receiver;
}
void GNSS::run()
{
//获得系统时间并输出
QString min = QDateTime::currentDateTime().toString("yyyyMMddhhmm");
//打开文本 以时间命名文件名字
QString fileName = "C:\\SensorsData\\BASLER\\code\\build-opencv-Desktop_Qt_5_8_0_MSVC2015_64bit-Debug\\GNSS_" + min + ".txt";//假设指定文件夹路径为D盘根目录
QFile f(fileName);
LONGLONG time_now=0;
QString s = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
QString a = QDateTime::currentDateTime().toString("yyyyMMddhhmm");
QString b = QDateTime::currentDateTime().toString("mmss");
while(!stopped)
{
while(receiver->hasPendingDatagrams()) //拥有等待的数据报
{
//qDebug() << "receive succeed ! " << endl;
QByteArray datagram; //拥于存放接收的数据报
//pendingDatagramSize为返回第一个在等待读取报文的size,
//resize函数是把datagram的size归一化到参数size的大小一样
datagram.resize(receiver->pendingDatagramSize());
//接收数据报,将其存放到datagram中
//将读取到的不大于datagram.size()大小数据输入到datagram.data()中,
//datagram.data()返回的是一个字节数组中存储数据位置的指针
receiver->readDatagram(datagram.data(),datagram.size());
//将数据报内容显示出来
QString HexData = datagram.toHex();
//判断数据是否完整
if(HexData.length() == 144)
{
//解析Hex数据
QString Status = HexData.mid(42,2);
qDebug() << "Status :" << Status << endl;
QString Latitude = HexData.mid(46,16);
qDebug() << "Latitude :" << Latitude << endl;
QString Longitude = HexData.mid(62,16);
qDebug() << "Longitude :" << Longitude << endl;
QString Altitude = HexData.mid(78,8);
qDebug() << "Altitude :" << Altitude << endl;
QString North_Velocity = HexData.mid(86,6);
qDebug() << "North_Velocity :" << North_Velocity << endl;
QString East_Velocity = HexData.mid(92,6);
qDebug() << "East_Velocity :" << East_Velocity << endl;
QString Down_Velocity = HexData.mid(98,6);
qDebug() << "Down_Velocity :" << Down_Velocity << endl;
QString Heading = HexData.mid(104,6);
qDebug() << "Heading :" << Heading << endl;
QString Pitch = HexData.mid(110,6);
qDebug() << "Pitch :" << Pitch << endl;
QString Roll = HexData.mid(116,6);
qDebug() << "Roll :" << Roll << endl;
//获得系统时间并输出
s = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
a = QDateTime::currentDateTime().toString("yyyyMMddhhmm");
b = QDateTime::currentDateTime().toString("mmss");
qDebug() << "min : " <<min<< endl;
time_now = b.toLongLong();
qDebug() << "time_now: " <<time_now<< endl;
//每10分钟保存一次
if(time_now % 1000 == 0)
{
qDebug() << "write again ! " <<time_now<< endl;
f.fileName() = "C:\\SensorsData\\BASLER\\code\\build-opencv-Desktop_Qt_5_8_0_MSVC2015_64bit-Debug\\GNSS_" + a + ".txt";
}
qDebug() << "time" << s;
if(!f.open( QIODevice::Append))
{
cout << "Open failed." << endl;
}
QTextStream txtOutput(&f);
txtOutput << s <<"$$"<< HexData<< "&&" << endl;
f.close();
}
else
{
qDebug() << "The data is not complete !" << endl;
}
}
}
}
/***********GNSS数据处理***********/
void GNSS::processPendingDatagram()
{
}
3 mainwindow.cpp
在ui界面新建两个button,分别是开始接收和停止接收,分别命名为StartGNSSBtn和StopGNSSBtn,然后在mainwindow.cpp中添加对应的槽函数
/***********开始GNSS数据接收***********/
void MainWindow::on_StartGNSSBtn_clicked()
{
if(!gnss.isRunning())
{
gnss.start();
ui->StartGNSSBtn->setEnabled(false);
ui->StopGNSSBtn->setEnabled(true);
}
else
{
qDebug() << "GNSS receive has started !!!" << endl;
}
}
/***********停止GNSS数据接收***********/
void MainWindow::on_StopGNSSBtn_clicked()
{
if(gnss.isRunning())
{
gnss.stop();
}
ui->StartGNSSBtn->setEnabled(true);
ui->StopGNSSBtn->setEnabled(false);
}
同时要记得在mainwindow.h中添加相关的变量和函数,添加头文件#include "gnss.h"
private:
//GNSS相关对象
GNSS gnss;
QPushButton *StartGNSSBtn;
QPushButton *StopGNSSBtn;
private slots:
//GNSS相关的槽函数
void on_StartGNSSBtn_clicked();
void on_StopGNSSBtn_clicked();
至此完成在新的线程里接收GNSS数据并初步的分割保存工作,下一步进行解析及显示
Qt接收GNSS数据
本文介绍如何使用Qt的QUdpSocket类接收GNSS数据,并通过创建新线程避免阻塞主线程。文中详细展示了从创建UDP接收端到解析数据的过程。
3637

被折叠的 条评论
为什么被折叠?



