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);
//}