【 Qt编写一个串口助手】

Qt编写一个串口助手

一、初始化

  1. 初始化需要注意的是,需要用到关于图形的qcustomplot 库,添加相关的.h和.cpp文件并在.pro文件下加上greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport

  2. 在添加图表时可以指定坐标轴,使每个图像对应他自己的坐标轴, ui->widget->addGraph(ui->widget->xAxis, ui->widget->yAxis); ui->widget->graph(0)->setPen(QPen(Qt::red));

  3. 在添加图例名称时需要注意加上customPlot->legend->setVisible(true);才会显示,

  4. radioButton取消自动互斥ui->radioButton->setAutoExclusive(false);ui->radioButton->setChecked(false);

二、后端数据处理

1. sysparam初始化串口的基本配置信息,并创建相对应的配置文件。
2. 数据接收
serial先在构造函数里给成员变量赋初值,添加默认命令到默认队列里,启动两个槽函数,一个由收到数据为信号调用数据处理函数,另一个由定时器为信号调用指令轮询函数。qt的信号槽机制可以跨越不同文件之间,让各个函数的调用更加方便。

SerialPort::SerialPort(QObject *parent) : QObject(parent)
{
    recvData.clear();

    regs.fAimPressure = 0;
    regs.fCurrentPressure = 0;

    QByteArray ba;

    ba = QByteArray::fromHex("BB11");

    pollingCmdList<<ba;

    connect(&port, SIGNAL(readyRead()),
            this, SLOT(dataHandler()));

    connect(&pollingTimer, SIGNAL(timeout()),
            this, SLOT(pollingHandler()));

}

(1)数据处理函数
串口发送过来的是字节数据,这里用一个共同体把一个8位长度为4的数组转化为32位的浮点型数据,判断接收数据的数组长度,长度超过4就将数据进行一个转换,并把转换后的数据放在类变量里。

void SerialPort::dataHandler()
{
    union {
        quint8 aucValue[4];
        float fValue;
    } nVal;

    QByteArray data = port.readAll();
    recvData.append(data);

    if (recvData.length() >= 4) {
        memcpy(nVal.aucValue, recvData.data(), 4);
        regs.fCurrentPressure = nVal.fValue;
        recvData.remove(0, 4);
        emit serialDataArrive();
    }
}

(2)指令轮询函数
处理的指令可以分为人为触发和默认触发,人为触发是指我们随机给单片机发送一些指令,默认指令是指单片机每次发送数据之前都需要一个指令,为了避免麻烦,就设置一个默认指令定时发送单片机。为了每次发送指令让人为指令的优先级最高,这里用两个队列去实现。 cmdQueue队列存放人为指令,pollingCmdList存放默认指令,每次执行前先判断cmdQueue是否为空,如果为空就将默认指令队列pollingCmdList插入到cmdQueue的队尾,如果cmdQueue非空就执行cmdQueue中的第一条指令,执行完就销毁。

void SerialPort::pollingHandler()
{
    if (!port.isOpen()) {
        return;
    }

    if (cmdQueue.isEmpty()) {
        cmdQueue.append(pollingCmdList);
    }

    if (!cmdQueue.isEmpty()) {
        QByteArray cmd = cmdQueue.first();
        currentCmd = cmd;
        sendCmd(cmd);
        cmdQueue.removeFirst();
    }
}

3.数据发送
数据发送给单片机需要在数据前面加一条指令AA12,同样我们要将一个32位的浮点型数据发送过去也需要一个共用体来转换。

void SerialPort::setPressure(float fVal) {
    union {
        quint8 aucValue[4];
        float fValue;
    } nVal;

    nVal.fValue = fVal;
    regs.fAimPressure=fVal;

    QByteArray sendCmd = QByteArray::fromHex("AA12") + QByteArray((const char *)(nVal.aucValue), 4);

    execCmd(sendCmd);
    qDebug()<< " sendCmd:"<<sendCmd;
}

三、前端处理
1.在类变量里创建4个动态数组用于存放曲线的数据源

    QVector<double> key;
    QVector<double> value;
    QVector<double> value2;
    QVector<double> value3;*

2.通过定时器触发让三个图层动态显示数据,把类变量中存放的数据添加到动态数组中

    value.push_back(serial.regs.fAimPressure);
    value2.push_back(serial.regs.fCurrentPressure);
    value3.push_back(serial2.regs.fForce);
    key.push_back(now);

3.通过一个pushButton让图例实现自动缩放和手动缩放之间来回切换。通过遍历三个动态数组找到一个最大值做自动缩放的最大值。

   if (autoRange) {
         double max = 0;
         double max2 = 0;
         foreach (double val, value) {
             if (val > max) {
                 max = val;
             }
         }
         foreach (double val, value2) {
             if (val > max) {
                 max = val;
             }
         }
         foreach (double val, value3) {
             if (val > max2) {
                 max2 = val;
             }
         }
         max += 10;
         max2 += 10;

4.让时间横轴进行缩放,如果时间超过一分钟时,将整个图例进行平移,没有的话就正常的移动。

  if (key.last() > key.first() + 60) {
             customPlot->xAxis->setRange(now - 60, now + 5);
         } else {
             customPlot->xAxis->setRange(key.first(), key.last() + 5);
         }

5.用lineEdit做一个消息提示框,当on_pushButton_set_clicked触发时设置lineEdit里的文字,延时半秒后将lineEdit隐藏

void MainWindow::on_pushButton_set_clicked()
{
    QByteArray data = ui->lineEdit->text().toUtf8();

    qDebug()<< " 设置值:"<<data;
    serial.setPressure(data.toFloat());

    ui->label_setTip->setStyleSheet("QLabel{border:1px solid rgb(0, 0, 0); background-color:rgb(255, 255, 255)}");
    ui->label_setTip->setText("设置成功!!");
    sleep(500);
    ui->label_setTip->setStyleSheet("background:transparent");
    ui->label_setTip->clear();

}

延时函数(非阻塞延时)

void MainWindow::sleep(unsigned int msec)  //msec为毫秒
{
    QTime reachTime = QTime::currentTime().addMSecs(msec);
    while (QTime::currentTime() < reachTime)
    {
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    }
}

6.同一按钮切换

void MainWindow::on_pushButton_clicked()
{

    ui->widget->yAxis2->setTickLabels(false);
    if(ui->pushButton->text() == "打开串口1")
    {


        QString portName = param.portBoard;
        serial.open(portName);
        ui->radioButton->setChecked(1);
        ui->pushButton->setFixedSize(75,23);//固定样式
        flushed =TRUE;
        ui->pushButton->setStyleSheet(
                    "QPushButton{"
                    "color:rgba(255,0,0);"//红色
                    "border: 1px solid rgb(178, 34, 34);"
                    "}"
                    "QPushButton:hover{"
                    "border: 1px solid rgb(255, 165, 0);"
                    "}");
        ui->pushButton->setText("关闭串口1");
    }
    else if(ui->pushButton->text()=="关闭串口1")
    {
        serial.close();
        flushed =FALSE;
        ui->radioButton->setChecked(0);

        ui->pushButton->setFixedSize(75, 23);
        ui->pushButton->setStyleSheet(
                    "QPushButton{"
                    "color:rgba(0,0,0);" //黑色
                    "border: 1px solid rgb(54, 100, 139);"
                    "}"
                    "QPushButton:hover{"
                    "border:1px solid rgb(0, 150, 136);"//橘红色
                    "}");
        ui->pushButton->setText("打开串口1");

}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小飞爱学习1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值