有段时间,做电赛题的时候,在那看波形调PID参数,因为要同时观察电压和两路电流,无奈只有一台示波器,遂有一想法,将单片机采集的电流数据通过串口发送给上位机,然后在上位机上以波形的形式显示出来,方便观察。因为时间问题,都是现学现用,整体做的很简陋,只是实现了要用到的功能,还请选择性浏览。
1.上位机是基于Qt5编写的,还用到了用于绘图第三方库--qcustomplot,具体使用可以百度,我这里用的比较简单,没花时间去琢磨。首先用Qt创建一个项目,然后在项目的.pro文件里添加,其中serialport是串口的,printsupport是绘图库qcustomplot的。
QT += serialport printsupport
2.相应的头文件,第一个是对串口的设置,第二个是得到串口的信息,第三个自然就是用于绘图的qcustomplot的头文件了。
#include
#include
#include "qcustomplot.h"
3.定义相关变量,
private:
QSerialPort SerialPort; //用于设置串口
QSerialPortInfo SerialPortInfo;//用于得到串口信息
int Clk ; //x轴的时间数
QCustomPlot *Plot; //定义一个窗口绘图的句柄
QVector XData;//x轴数据
QVector YData;//线1的y轴数据
QVector Y1Data;//线2的y轴数据
QCustomPlot *PlotV; //定义另一个窗口绘图的句柄
QVector Y2Data;
QVector Y3Data;
初始化相关变量
XData.resize(50); //分配空间
XData.value(0,1);
YData.resize(50);
Y1Data.resize(50);
Y2Data.resize(50);
Y3Data.resize(50);
ui->horizontalAMax->setRange(600,3000);
ui->horizontalAMax->setValue(600);
ui->horizontalAMin->setRange(0,600);
ui->horizontalAMin->setValue(0);
ui->horizontalVMax->setRange(500,800);
ui->horizontalVMax->setValue(600);
ui->horizontalVMin->setRange(0,500);
ui->horizontalVMin->setValue(400);
Plot = ui->widget; //指定窗口用于显示波形
Plot->addGraph(); //添加一条线
Plot->addGraph(); //再添加一条线
Plot->graph(0)->setPen(QPen(Qt::red)); //设置第一根线的颜色为红色
Plot->graph(1)->setPen(QPen(Qt::blue)); //设置第二根线的颜色为蓝色
Plot->xAxis->setLabel("mS"); //设置x轴的标签
Plot->yAxis->setLabel("mA"); //设置y轴的标签
// Plot->rescaleAxes(true);
Plot->yAxis->setRange(0,700); //初始化y轴的范围
Plot->xAxis->rescale(true); //让x轴自动随着数变化
PlotV = ui->widget_C;
PlotV->addGraph();
PlotV->addGraph();
PlotV->graph(0)->setPen(QPen(Qt::red));
PlotV->graph(1)->setPen(QPen(Qt::blue));
PlotV->xAxis->setLabel("mS");
PlotV->yAxis->setLabel("Count");
PlotV->yAxis->setRange(400,600);
PlotV->xAxis->rescale(true);
GraphShow(); //给图形赋值
InitPort(); //初始化串口
QTimer::singleShot(80,this,&Widget::ReadPort);//定一定时器,方便接收数据
Clk = 0; //x轴的时间数,初试为0
3.串口的初始化和出口数据的读取
void Widget::InitPort() //判断当前是否有效的串口,并得到相关得数据
{
//遍历所有有效的串口,得到每个有效串口得数据
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
qDebug() << "Name :"<comboBoxCom->addItem(info.portName());
serial.close();//这里只是起判定效果,不用以打开,还得关闭当前串口,方便查询其他串口
}
}
}
//这个是开启按键的槽函数,如果有有效的串口,然后进行打开操作,也可以充当关闭串口的作用
void Widget::on_pushButtonS_clicked()
{
//判断当前程序处于什么状态中,如果没有串口使用,则进入“开启串口”
if(ui->pushButtonS->text() == "开启串口")
{ //得到当前串口栏得数据
SerialPort.setPortName(ui->comboBoxCom->currentText());
if(SerialPort.open(QIODevice::ReadOnly))
{
SerialPort.setBaudRate(ui->comboBoxBaut->currentText().toInt());//设置波特率
SerialPort.setDataBits(QSerialPort::Data8);//设置数据位为8位
SerialPort.setParity(QSerialPort::NoParity);//没有奇偶校验位
SerialPort.setFlowControl(QSerialPort::NoFlowControl);//没有流控制
SerialPort.setStopBits(QSerialPort::OneStop);//设置一个停止位
ui->pushButtonS->setText("关闭串口"); //更改按键状态
}
else{
qDebug() << "串口没有打开";
return;
}
}else if(ui->pushButtonS->text() == "关闭串口")
{
SerialPort.close();
ui->pushButtonS->setText("开启串口");
}
else{
qDebug() <<"无效操作";
}
}
//获取串口数据,我这里是采用每隔40ms来获取一次数据
void Widget::ReadPort()
{
QTimer::singleShot(40,this,&Widget::ReadPort);
if(SerialPort.isOpen() == false)
return;
//得到串口数据
QByteArray temp = SerialPort.readAll();
if(temp.isEmpty())
return;
//将数据进行文本化显示
ui->textEditR->append(QString(temp));
GetData(QString(temp));//处理当前数据,得出有效数据,这个函数实现是按要求来的,就不贴出来了
GraphShow();
}
4.波形的绘制--GraphShow函数的实现
void Widget::GraphShow()
{
Plot->graph(0)->setData(XData,YData);
Plot->graph(1)->setData(XData,Y1Data);
Plot->yAxis->setRange(Slither_aMin,Slither_aMax);
Plot->xAxis->rescale(true);
Plot->replot();//重新绘制
PlotV->graph(0)->setData(XData,Y2Data);
PlotV->graph(1)->setData(XData,Y3Data);
PlotV->yAxis->setRange(Slither_vMin,Slither_vMax);
PlotV->xAxis->rescale(true);
PlotV->replot();
}
5.另外就是一些按键和滑动栏的槽函数,视具体要求实现,就不贴出来了。其中刷新按键,是获取当前有效串口,清除按键是清除text窗口的文本信息,四个滑行分别是调整相应窗口的y轴的上限和下限,方便观察波形。
6.总结,其实qcustomplot和串口相关的函数使用还是挺简单的,其中qcustomplot我只是用到了点皮毛,看官方提供的demo,可是非常好看和实用的。
最后用来观察波形的时候,还是挺不错的。因为时间有点远,没有相应的图贴出来了,还请见谅。学习,共勉。