前言
本文主要涉及上位机对接收的串口数据处理,LCD Number控件的使用。之前的一篇写一个简单的LED控制主要是串口发出数据,这里再看一下怎么接收数据处理数据,这样基本就对串口上位机有简单的认识了。
LCD Number显示时间
这一小节通过用一个LCD Number实时显示时间的例程认识一下LCD Number控件。
新建一个widget示例工程,前面的文章都有相关内容,请移步查阅,这里不赘述。
双击widget.ui打开 Qt 设计器界面,拉一个LCD Number到合适位置
拉大一点:
这里说一下QT开发的大概模式,和C# 开发很像,这里是.ui文件是UI设计,同时相关源文件配合,如果UI设计不能直接设置的,就必须通过源码实现,当然UI设计器主要还是设置控件的位置大小颜色和一些基本参数之类的。ui文件是可有可无的,即使没有ui文件,完全通过代码添加控件,设定控件参数位置等也是完全可行的。
其余的就按下面的代码改一下就行了。
整体源码:
widget.cpp文件:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
/* 设置显示的位数 8 位 */
ui->lcdNumber->setDigitCount(8);
/* 设置样式 */
ui->lcdNumber->setSegmentStyle(QLCDNumber::Flat);
/* 设置 lcd 显示为当前系统时间 */
QTime time = QTime::currentTime();
/* 设置显示的样式 */
ui->lcdNumber->display(time.toString("hh:mm:ss"));
timer = new QTimer(this);
/* 设置定时器 1000 毫秒发送一个 timeout()信号 */
timer->start(1000);
/* 信号槽连接 */
connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeOut()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerTimeOut()
{
/* 当定时器计时 1000 毫秒后,刷新 lcd 显示当前系统时间 */
QTime time = QTime::currentTime();
/* 设置显示的样式 */
ui->lcdNumber->display(time.toString("hh:mm:ss"));
}
widget.h文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QLCDNumber>
#include <QTimer>
#include <QTime>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
/* 声明 QTimer 对象 */
QTimer *timer;
private slots:
/* 槽函数 */
void timerTimeOut();
};
#endif // WIDGET_H
其余文件保持默认。
效果:
串口数据处理,LCD Number显示电压电流
串口协议是JSON格式:类似{“Cur”:118,“Vol”:7587},电流单位mA,电压单位mV
双击.ui文件打开UI设计器,通过拖动的方式添加控件,如下图所示放置,红色框是Label,蓝色框是Combo Box,黄色框是两个Push Button,棕色框是LCD Number,其中的文字都可在放置控件后双击改之:
串口部分与这篇文章相似:QT C++入门学习(2) QT Creator写一个简单的上位机控制LED,可作参考
Label可以通过font属性调整字体和大小:
LCD Number可以通过digitCount属性设定最大显示位数,这里保持默认5位即可:
.pro文件中添加串口模块:
程序源码:
widget.h文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QLCDNumber>
#include <QSerialPort>
#include <QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
QSerialPort *serialPort;//定义串口指针
private slots:
/*以下为widget.ui文件中点击“转到槽”自动生成的函数*/
void on_openBt_clicked();
void on_btnSerialCheck_clicked();
void DateRead();
};
#endif // WIDGET_H
widget.cpp文件:
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
//解析json格式类
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QStringList serialNamePort;
serialPort = new QSerialPort(this);
ui->serailCb->clear();
//通过QSerialPortInfo查找可用串口
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->serailCb->addItem(info.portName());
}
connect(serialPort,SIGNAL(readyRead()),this,SLOT(DateRead()));/*手动连接槽函数*/
}
/*打开串口*/
void Widget::on_openBt_clicked()
{
// 初始化串口属性,设置 端口号、波特率、数据位、停止位、奇偶校验位数
serialPort->setPortName(ui->serailCb->currentText());
serialPort->setBaudRate(ui->baundrateCb->currentText().toInt());
serialPort->setDataBits(QSerialPort::Data8);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setParity(QSerialPort::NoParity);
// 根据初始化好的串口属性,打开串口
// 如果打开成功,反转打开按钮显示和功能。打开失败,无变化,并且弹出错误对话框。
if(ui->openBt->text() == "打开串口"){
if(serialPort->open(QIODevice::ReadWrite) == true){
ui->openBt->setText("关闭串口");
// 让端口号下拉框不可选,避免误操作(选择功能不可用,控件背景为灰色)
ui->serailCb->setEnabled(false);
}else{
QMessageBox::critical(this, "错误提示", "串口打开失败!!!\r\n该串口可能被占用\r\n请选择正确的串口");
}
}else{
serialPort->close();
ui->openBt->setText("打开串口");
// 端口号下拉框恢复可选,避免误操作
ui->serailCb->setEnabled(true);
}
}
//检测通讯端口槽函数
void Widget::on_btnSerialCheck_clicked()
{
ui->serailCb->clear();
//通过QSerialPortInfo查找可用串口
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->serailCb->addItem(info.portName());
}
}
void Widget::DateRead() //接收数据
{
QByteArray recvData=serialPort->readAll();
//解析 JSON格式
QString receive =QString::fromLocal8Bit(recvData.constData());
QJsonDocument doc=QJsonDocument::fromJson(receive.toUtf8());
QJsonObject obj=doc.object();
QJsonValue Current =obj.value("Cur");
QJsonValue Voltage =obj.value("Vol");
ui->current_Num->display(Current.toInt());
ui->voltage_Num->display(Voltage.toInt());
}
Widget::~Widget()
{
delete ui;
}
验证:
(方法:通过两个USB转串口模块TX和RX对接,其中一个端口通过串口助手发送JSON字符,注意波特率需相同)
LCD Number还可以更改颜色样式:
通过styleSheet属性即可更改:
color是字体颜色,background-color是背景色