Qt qextserial进行串口数据采集,qcustomplot进行绘图,曲线实时显示横纵坐标辅助线
目的、要求:
A.读取RS422接口接收到的全部数据;
1.通过接口读取板卡采集的数据,采用多线程,读取数据和解析数据在主线程,绘制曲线在另一个新的线程。COM和API接口见附件1.板卡用户手册。
2.根据接收到的数据,需要先判定是返参帧A还是返参帧B,每一帧具有27个字节,每帧依据“帧头”和“校验和”来判定。
需要注意:
a)数据流起始位置并不一定是“帧头”。
b)数据流中可能存在无效的数据包,需要注意判定逻辑,以免丢失有效数据。
B.能够依据协议对数据进行解析并存储;
1.要求对返参帧A和返参帧B数据分别解析,详细的解析与处理要求见附件2。附件2中需要用到的解析协议见附件3。
2.将接收到的返参帧A和返参帧B分别存储在文档不同的sheet中,文档格式为".xlsx",允许用户在软件界面上以点击按钮的形式选择数据存储开始/结束,允许用户选择设置路径。
3.存储内容包括附件2表中全部解析内容,每一项解析内容对应存储在文档中一列,存储数据为解析后未经数据处理的数据。
C.对解析后的一些数据,以曲线的形式显示。
1.软件需对返参帧A和返参帧B的部分解析内容进行实时曲线绘制,需要绘制曲线的参数见附件4。共15个曲线图。
2.通过“选项卡”的形式将不同类型曲线放置在不同选项卡页面中。
3.要求曲线能根据接收解析后的数据点进行动态实时更新,从右向左,横坐标代表点的个数,曲线对应的横坐标刻度要一同向左更新移动。
4.要求曲线窗口有图标题,有横纵坐标标题;如果一个曲线窗口中有多条曲线,要求用不同颜色区分,对不同曲线有标注;用户可选择仅显示其中某一条或某两条曲线;
5.曲线要求正常显示为1000个数据点,缓存区要求存180000个数据点,可在曲线窗口上左右拖拽以查看180000中的各个1000个数据点的显示区间,超出180000个数据点缓存区后,每进入一个新的数据点,则顺次清除一个原数据点。曲线横、纵坐标范围允许用户调整,可进行2、4、6、8倍的4档放大曲线局部判读。
6.鼠标移动到曲线上的数据点上时,要求有指向横、纵坐标的辅助线。
简介:
考虑到这个要移植到硬件上,到时候交叉编译后的Qt环境需要串口模块的支持。所以选用了第三方的chua串口通讯模块qextserial进行串口通讯。绘图使用的第三方的qcustomplot。串口模块放到线程里,数据处理和绘图部分放到了主线程。这个地方主要麻烦的是对通讯帧的解析。首先分为A B两种mo's模式,每个字节对应的有不同的含义。有些字节的某几位对应的不同的含义。剩下的就是数据的辅助线问题了。辅助线继承了QCustomPlot,然后重写了鼠标事件和其他的一些事件。
效果:
代码:
#ifndef MHCUSTOMPLOT_H
#define MHCUSTOMPLOT_H
#include "mhtracer.h"
#include "qcustomplot.h"
#include <QObject>
#include <QList>
class MhCustomPlot : public QCustomPlot
{
Q_OBJECT
public:
MhCustomPlot(QWidget *parent = 0);
protected:
virtual void mouseMoveEvent(QMouseEvent *event);
virtual void enterEvent(QEvent *event);
virtual void leaveEvent(QEvent *event);
//virtual void mouseDoubleClickEvent(QMouseEvent *event);
//signals:
//void legendDoubleClickChilden(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event);
public:
//设置是否显示鼠标追踪器
//是否显示
void showTracer(bool show);
// 是否显示鼠标追踪器
bool isShowTracer(){return m_isShowTracer;}
private:
bool m_isShowTracer;//是否显示追踪器(鼠标在图中移动,显示对应的值)
MhTracer *m_xTracer;//x轴
MhTracer *m_yTracer;//y轴
QList<MhTracer *> m_dataTracers;//
MhTraceLine *m_lineTracer;//直线
};
#endif // MHCUSTOMPLOT_H
#include "mhcustomplot.h"
MhCustomPlot::MhCustomPlot(QWidget *parent)
:QCustomPlot(parent)
,m_isShowTracer(false)
,m_xTracer(Q_NULLPTR)
,m_yTracer(Q_NULLPTR)
,m_dataTracers(QList<MhTracer *>())
,m_lineTracer(Q_NULLPTR)
{
}
//设置是否显示鼠标追踪器
//是否显示
void MhCustomPlot::showTracer(bool show)
{
m_isShowTracer = show;
if(m_xTracer)
m_xTracer->setVisible(m_isShowTracer);
///
if(m_yTracer)
{
m_yTracer->setVisible(m_isShowTracer);
}
foreach (MhTracer *tracer, m_dataTracers)
{
if(tracer)
tracer->setVisible(m_isShowTracer);
}
if(m_lineTracer)
m_lineTracer->setVisible(m_isShowTracer);
}
void MhCustomPlot::mouseMoveEvent(QMouseEvent *event)
{
QCustomPlot::mouseMoveEvent(event);
if(m_isShowTracer)
{
//当前鼠标位置(像素坐标)
int x_pos = event->pos().x();
int y_pos = event->pos().y();
//qDebug() << "x_pos:" << x_pos << "y_pos:" << y_pos;
//像素坐标转成实际的x,y轴的坐标
float x_val = this->xAxis->pixelToCoord(x_pos);
float y_val = this->yAxis->pixelToCoord(y_pos);
if(Q_NULLPTR == m_xTracer)
m_xTracer = new MhTracer(this, MhTracer::XAxisTracer);//x轴
m_xTracer->updatePosition(x_val, y_val);
if(Q_NULLPTR == m_yTracer)
m_yTracer = new MhTracer(this, MhTracer::YAxisTracer);//y轴
m_yTracer->updatePosition(x_val, y_val);
int nTracerCount = m_dataTracers.count();
int nGraphCount = graphCount();
if(nTracerCount < nGraphCount)
{
for(int i = nTracerCount; i < nGraphCount; ++i)
{
MhTracer *tracer = new MhTracer(this, MhTracer::DataTracer);
m_dataTracers.append(tracer);
}
}
else if(nTracerCount > nGraphCount)
{
for(int i = nGraphCount; i < nTracerCount; ++i)
{
MhTracer *tracer = m_dataTracers[i];
if(tracer)
{
tracer->setVisible(false);
}
}
}
for (int i = 0; i < nGraphCount; ++i)
{
MhTracer *tracer = m_dataTracers[i];
if(!tracer)
tracer = new MhTracer(this, MhTracer::DataTracer);
tracer->setVisible(true);
tracer->setPen(this->graph(i)->pen());
tracer->setBrush(Qt::NoBrush);
tracer->setLabelPen(this->graph(i)->pen());
auto iter = this->graph(i)->data()->findBegin(x_val);
double value = iter->mainValue();
// double value = this->graph(i)->data()->findBegin(x_val)->value;
tracer->updatePosition(x_val, value);
}
if(Q_NULLPTR == m_lineTracer)
m_lineTracer = new MhTraceLine(this,MhTraceLine::Both);//直线
m_lineTracer->updatePosition(x_val, y_val);
this->replot(QCustomPlot::rpQueuedReplot);//曲线重绘
}
}
void MhCustomPlot::enterEvent(QEvent *event)
{
//QCustomPlot::enterEvent(event);
//qDebug() << "鼠标进入";
m_isShowTracer = true;
if(m_xTracer)
m_xTracer->setVisible(m_isShowTracer);
if(m_yTracer)
{
m_yTracer->setVisible(m_isShowTracer);
}
foreach (MhTracer *tracer, m_dataTracers)
{
if(tracer)
tracer->setVisible(m_isShowTracer);
}
if(m_lineTracer)
m_lineTracer->setVisible(m_isShowTracer);
this->replot(QCustomPlot::rpQueuedReplot);
}
void MhCustomPlot::leaveEvent(QEvent *event)
{
//QCustomPlot::leaveEvent(event);
//qDebug() << "鼠标离开";
m_isShowTracer = false;
if(m_xTracer)
m_xTracer->setVisible(m_isShowTracer);
if(m_yTracer)
{
m_yTracer->setVisible(m_isShowTracer);
}
foreach (MhTracer *tracer, m_dataTracers)
{
if(tracer)
tracer->setVisible(m_isShowTracer);
}
if(m_lineTracer)
m_lineTracer->setVisible(m_isShowTracer);
this->replot(QCustomPlot::rpQueuedReplot);
}
//void MhCustomPlot::mouseDoubleClickEvent(QMouseEvent *event)
//{
// QCustomPlot::mouseDoubleClickEvent(event);
//}