一、展示效果
二、绪论
1.教程背景
因为项目涉及到超声波传感器,想要做一个上位机展示超声波传感器读取到的距离信息,网上很多教程都是关于普通串口助手展示文本数据的,所以在此将串口读取和曲线展示两个功能显示在一起。这个串口助手删减了很多功能,只保留了读取功能,并没有发送功能(用不上),所以实现比较简单。
2.工程架构
chart源文件主要用于图标的设置,serial源文件主要用于串口的设置。
3.serial头文件
#ifndef SERIAL_H
#define SERIAL_H
#include <QMainWindow>
#include "ui_serial.h"
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QString>
#include <QDateTime>
#include <QTimer>
#include <qmath.h>
#include <QDebug>
#include <QChartView>
#include <QSplineSeries>
#include <QValueAxis>
#include <QtCharts>
using namespace QtCharts;
QT_BEGIN_NAMESPACE
namespace Ui { class serial; }
QT_END_NAMESPACE
class serial : public QMainWindow
{
Q_OBJECT
public:
serial(QWidget *parent = nullptr);
~serial();
private slots:
void btn_serial_check(bool);
void btn_open_port(bool);
void btn_close_port(bool);
void receive_data(void);
void btn_clear_rev(bool);
void updatechart();
private:
Ui::serial *ui;
void ChartInit();
void system_init();
QSerialPort global_port;
QChart *m_chart ;
QChartView *m_chartView;
QValueAxis *axisX;
QValueAxis *axisY;
QSplineSeries *series ;
QTimer *m_timer;
};
#endif
三、UI界面
三、曲线的产生
1.Qt Charts组件的使用
在serial.pro加上charts,按Ctril+S进行保存,可能会报错。解决方案:解决思路链接。 在确认.pro文件中添加了相应语句并保存之后,需要在程序头文件中添加
#include <QtCharts>
using namespace QtCharts;
2.chart源文件
#include "serial.h"
void serial::ChartInit()
{
m_chart = new QChart();
m_chartView = new QChartView(m_chart,this);
m_chart = m_chartView->chart();
m_chartView->setRubberBand(QChartView::NoRubberBand);
m_chartView->setRenderHint(QPainter::Antialiasing);
axisX = new QValueAxis;
axisY = new QValueAxis;
axisX->setRange(0, 10);
axisY->setRange(-1, 1);
axisX->setLabelFormat("%d");
axisY->setLabelFormat("%0.2f");
axisX->setGridLineVisible(true);
axisY->setGridLineVisible(true);
axisX->setTickCount(10+1);
axisY->setTickCount(10+1);
axisX->setMinorTickCount(5);
axisX->setTitleText("x");
axisY->setTitleText("距离cm");
m_chart->addAxis(axisX, Qt::AlignBottom);
m_chart->addAxis(axisY, Qt::AlignLeft);
m_chart->setTitle("y = sin(x)");
m_chart->legend()->hide();
m_chart->legend()->setLayoutDirection(Qt::LeftToRight);
m_chart->legend()->setAlignment(Qt::AlignLeft);
series = new QSplineSeries(this);
series->setName(QString("y=sinx"));
m_chart->addSeries(series);
series->attachAxis(axisX);
series->attachAxis(axisY);
ui->verticalLayout_2->addWidget(m_chartView);
m_timer = new QTimer(this);
m_timer->start(100);
connect(m_timer,SIGNAL(timeout()),this,SLOT(updatechart()));
}
void serial::updatechart()
{
axisX->setRange(0,points*0.1);
series->append(points*0.1,sin(points*0.1));
points++;
}
- QSplineSeries: 用于创建有由一系列数据组成的曲线.类似的还有QPieSeries(饼图数据). QLineSeries(折线数据)。
- QChart: 图表界面,用来管理图表内容,颜色,大小等。
- QChartView: 负责显示QChart。
通过对应的函数设置坐标轴参数、图标参数、曲线参数。 通过上述代码将图表添加到控件,这个控件对应的位置如下图箭头所示,就是个layout控件。 到了这一步还没开始通过串口读取数据,所以自己用定时器先产生数据模拟串口数据,通过updatechart函数不断更新数据。 通过setRange函数不断拓宽x轴范围,通过appedf函数给曲线增加新的点。
3. 初步实现效果
下一步完成串口的设置,并将串口读取的数据显示出来。
四、串口设置
1.准备工作
在pro文件添加serialport。 添加对应头文件,在上面可以复制。 对象初始化函数包含一个串口初始化函数,一个图标初始化函数。
serial::serial(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::serial)
{
ui->setupUi(this);
system_init();
ChartInit();
}
2.用户系统初始化函数
void serial::system_init()
{
ui->cmd_port_name->clear();
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->cmd_port_name->addItem(info.portName());
}
ui->lab_status->setStyleSheet("color:red");
connect(ui->btn_serial,&QPushButton::clicked,this,&serial::btn_serial_check);
connect(ui->btn_open,&QPushButton::clicked,this,&serial::btn_open_port);
connect(&global_port,&QSerialPort::readyRead,this,&serial::receive_data);
connect(ui->btn_clear,&QPushButton::clicked,this,&serial::btn_clear_rev);
}
在标准C++中,并没有foreach关键字。但是在QT中,可以使用这一个关键字,其主要原因是QT自己增加了这一个关键字,就像slots和signals、emit等一样。增加的foreach关键字在编译时会进行预处理。 其用法为:foreach (varItem , Items) // foreach(variable ,container)
availablePorts函数:,以QList数据类型返回系统可用的串口清单。 addItem函数:是组合框QComboBox类的函数,将函数带着的文本增加至组合框内的选项中。 setStyleSheet函数:设置指定样式。
利用connect函数,将【检测通讯端口】【打开】【清除】按键的clicked信号与对应的槽函数连接在一起。
3.检测通讯端口槽函数
和系统初始化函数里面的操作是一样的,就是更新端口。
void serial::btn_serial_check(bool)
{
ui->cmd_port_name->clear();
//通过QSerialPortInfo查找可用串口
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
//将可用串口添加到端口显示框
ui->cmd_port_name->addItem(info.portName());
}
}
4.打开选择端口槽函数
void serial::btn_open_port(bool)
{
//port name 设置端口
global_port.setPortName(ui->cmd_port_name->currentText());
//baud rate 设置波特率为115200
global_port.setBaudRate(QSerialPort::Baud115200);
//parity 设置无校验位
global_port.setParity(QSerialPort::NoParity);
//data bits 设置数据位8位
global_port.setDataBits(QSerialPort::Data8);
//stop bits 设置停止位1位
global_port.setStopBits(QSerialPort::OneStop);
//port open 打开选择端口
bool ret = global_port.open(QIODevice::ReadWrite);
if(ret){
//打开成功更新状态
ui->lab_status->setText("Connected");
//设置串口状态标签为绿色 表示已连接状态
ui->lab_status->setStyleSheet("color:green");
}
}
cmd_port_name是选择端口号那个组合框,currentText表示当前端口号的名称。
因为应用场景固定,所以直接给定了串口的格式要求,而通过组合框不需要选择。通过QSerialPort类的函数进行波特率、校验位、数据位、停止位的设定。
open函数:通过固定模式打开串口,成功返回true,否则返回false。模式必须是 QIODevice::ReadOnly, QIODevice::WriteOnly, or QIODevice::ReadWrite.,其他模式不支持。这里我们选择是读写模式。
最后对返回值ret进行判断,连接成功则将状态栏文本改为“Connected”,颜色也改为绿色。
5.关闭选择端口槽函数
void serial::btn_close_port(bool)
{
global_port.close();
//关闭端口后显示状态
ui->lab_status->setText("DisConnected");
ui->lab_status->setStyleSheet("color:red");
}
colse函数和open函数是对应的,一个打开,一个关闭。
6.数据更新函数和清除文本函数
float max=0;
void serial::receive_data(void)
{
QByteArray array = global_port.readAll();
QString str_rev;
if(array.toFloat()>max)
max=array.toFloat();
axisY->setRange(0,max+2);
axisX->setRange(0,points);
series->append(points,array.toFloat());
points++;
if(ui->chk_rev_time->checkState() == Qt::Checked)
{
QDateTime nowtime = QDateTime::currentDateTime();
str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";
str_rev += QString(array).append("\r\n");
}
else
{
str_rev += QString(array).append("\r\n");
}
ui->pte_rcv->insertPlainText(str_rev);
}
void serial::btn_clear_rev(bool)
{
ui->pte_rcv->clear();
}
通过QByteArray数据类型承接串口数据,然后通过toFloat函数转换为float数据类型的数值,通过append函数添加到曲线当中去。
文本方面通过insertPlainText函数添加字符串,通过clear函数删除字符串。
pte_ecv控件就是那个多行编辑框控件,如下图。
7.其他修正
测试用的定时器可以注释或删除,更新函数updatechart也可以删除。 将设置坐标轴范围的代码注释,因为这是y=sinx曲线的范围,对应超声波显示已经不适用了。 通过单片机printf函数随机发送float数据类型数据。
QT中foreach的使用 Qt绘制实时曲线图形简单例程 - Qt实时绘图
|