基于uFUN开发板的心率计(三)Qt上位机的实现

前言

上两周利用周末的时间,分别写了基于uFUN开发板的心率计(一)DMA方式获取传感器数据基于uFUN开发板的心率计(二)动态阈值算法获取心率值,介绍了AD采集传感器数据和数据的滤波处理获取心率值。这篇文章主要是介绍Qt上位机如何实现波形的显示,串口数据的解析,以及一些小细节实现。这篇文章写完,uFUN心率计这个小项目就算结束了,最近又做了个uFUN开发板的扩展板,在微信群里的朋友都已经看到了,后面会做一些好玩的东西,大家要保持关注哈!

关于Qt

Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些宏,Qt很容易扩展,并且允许真正地组件编程。2008年,Qt Company科技被诺基亚公司收购,Qt也因此成为诺基亚旗下的编程语言工具。2012年,Qt被Digia收购。2014年4月,跨平台集成开发环境Qt Creator 3.1.0正式发布,实现了对于iOS的完全支持,新增WinRT、Beautifier等插件,废弃了无Python接口的GDB调试支持,集成了基于Clang的C/C++代码模块,并对Android支持做出了调整,至此实现了全面支持iOS、Android、WP,它提供给应用程序开发者建立艺术级的图形用户界面所需的所有功能。基本上,Qt 同 X Window 上的 Motif,Openwin,GTK 等图形界 面库和 Windows 平台上的 MFC,OWL,VCL,ATL 是同类型的东西。——来自百度百科

串口数据的解析和显示

pro文件添加串口支持:

QT += serialport

头文件包含:

#include <QSerialPort>
#include <QSerialPortInfo>

串口对象的定义:

QSerialPort serial;

启动自动搜索本机串口并添加到下拉框:

foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
    ui->cbb_com->addItem(info.portName());  //串口号下拉菜单,增加一个条目,为串口号COM4
    qDebug() << "串口搜索完成";
}

串口的打开:

    serial.setPortName(ui->cbb_com->currentText());     //设置串口号、
    serial.setBaudRate(ui->cbb_baud->currentText().toInt());    //设置波特率
    serial.setDataBits(QSerialPort::Data8);     //设置串口数据位8
    serial.setParity(QSerialPort::NoParity);    //无校验位
    serial.setStopBits(QSerialPort::OneStop);   //1位停止位
    serial.setFlowControl(QSerialPort::NoFlowControl);
    if(!serial.open(QIODevice::ReadWrite))
    {
        QMessageBox::critical(NULL, "提示", "串口打开失败");
        return;
    }

串口的关闭:

    serial.close();

关联信号与槽函数:

connect(&serial, & QSerialPort::readyRead, this, &Pulse::serialPort_readyRead);

串口通讯协议:

电压值的显示:S+传感器数值+\r\n
心率值的显示:B+心率值+\r\n

槽函数里进行串口数据的解析:

//串口数据接收并解析
void Pulse::serialPort_readyRead()
{
    bool ok1, ok2;
    static double x;
    double SensorValue;
    QByteArray rx_buf= serial.readAll();;
    int len = rx_buf.length();
    //    qDebug() << rx_buf << " - " << len;
    x += 0.1;
    if(rx_buf.startsWith("S") && rx_buf.endsWith("\r\n"))
    {
        int indx1 = rx_buf.indexOf("\r\n");
        QString str1 = rx_buf.mid(1, indx1 - 1);
        SensorValue = str1.toDouble(&ok1) * 3.3 / 4096 ;
        if(ok1 && !stopFlag)
        {
            if(SensorValue > 2.5)
                SensorValue = 2.5;
            if(SensorValue < 1.4)
                SensorValue = 1.4;
            //            qDebug() << " 电压值: "<< SensorValue;
            QString dis_SIG;
            dis_SIG.sprintf("%.2f v", SensorValue);
            ui->lbe_SIG->setText(dis_SIG);
            ui->widget->graph(0)->addData(x, SensorValue);
            ui->widget->xAxis->setRange(x, 40, Qt::AlignRight);
            ui->widget->replot();
            //            ui->widget->replot(QCustomPlot::rpQueuedReplot);
        }
    }
    else if(rx_buf.startsWith("B") && rx_buf.endsWith("\r\n"))
    {
        int index2 = rx_buf.indexOf("\r\n");
        QString str2 = rx_buf.mid(1, index2 - 1);
        BMP = str2.toInt(&ok2);
        qDebug() << "心率值: "<< str2;
        if(ok2 && !stopFlag)
        {
            QString dis_BPM;
            ui->lbe_BPM->setText(QString::number(BMP,10) + "/min");
        }
    }
    else
    {
        x = 0;
        serial.close(); //关闭串口
        this->ui->btn_uart_Ctrl->setText("打开串口");
        QMessageBox::warning(this, "警告", "串口数据格式错误!");
    }
    rx_buf.clear();
}

关于串口的详细使用,可以参考最开始学习Qt时做的一个练手项目:Qt小项目之串口助手控制LED

QCustomplot绘图库的使用

1.添加库文件到工程

库文件的下载:QCustomPlot-source.tar.gz

或者到官方网站下载最新版的库文件:qcustomplot

主要就两个文件qcustomplot.hqcustomplot.cpp,把两个文件添加到Qt工程

2.pro文件添加

qcustomplot包含了一些打印的功能,所以需要包含打印的支持

QT += printsupport
3.UI界面添加Widget绘图窗口

UI界面添加Widget绘图窗口,并右键把它提升为QCustomPlot类,Qt提升控件时,通常提升的类名称中,每个单词的首字母必须大写,否则无法识别,如这里必须写成QCustomPlot而不能写成Qcustomplot或qcustomplot

4.Widget的初始化:
ui->widget->setBackground(QBrush(Qt::white));   //设置背景颜色
ui->widget->axisRect()->setupFullAxesBox();//在坐标轴右侧和上方画线,和X/Y轴一起形成一个矩形
ui->widget->legend->setFont(QFont("Helvetica", 12)); //设置图例字体和大小
ui->widget->legend->setVisible(true);       //使能图例可见
ui->widget->xAxis->setLabel("时间"); //设置X轴文字标注
ui->widget->yAxis->setLabel("电压值");//设置Y轴文字标注
ui->widget->yAxis->setRangeLower(1);
ui->widget->yAxis->setRangeUpper(3);
//    ui->widget->yAxis->setRangeLower(-2);            //设置y轴最小值
//    ui->widget->yAxis->setRangeUpper(3);            //设置y轴最大值
//    ui->widget->graph(0)->setLineStyle(QCPGraph::lsLine);
//    ui->widget->graph(0)->setPen(QPen(Qt::blue));
ui->widget->addGraph();
QPen pen(Qt::red, 1.5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
ui->widget->graph(0)->setPen(pen);
ui->widget->graph(0)->setName("心跳曲线");
5.实时显示串口发来的电压值

在串口接收的槽函数中实现:

ui->widget->graph(0)->addData(x, SensorValue);
ui->widget->xAxis->setRange(x, 40, Qt::AlignRight);
ui->widget->replot();

QCustomplot是Qt开发环境下一个很强大而又简单的绘图库,关于QCustomplot库的详细使用方法,可以参考这篇文章:Qt-QCustomplot画静态、动态曲线教程图解

软件自动更新功能的实现

这个上位机包含了一个检测更新的小功能,如果有新版本,点击检查更新会弹出如下窗口,如果点击去下载,会直接跳转到浏览器,创建下载任务。

详细的实现思路和过程,可以看我写的笔记:Qt实现软件自动更新的一种简单方法

软件的下载

有需要这个上位机软件的朋友,可以直接下载:uFun_Pulse_v1.1.exe

总结

这两周利用周末的时间,把uFUN开发板+传感器实现心率计这个小项目的实现过程写完了,整体来看,写的不是很详细,但具体的实现思路介绍的还算清晰,希望能对大家有一些帮助。上位机目前还有一些小BUG待解决,等有点时间,再继续完善。

uFUN评测系列文章


感谢关注!

### Qt 在医疗设备上位机开发中的应用 Qt 是一个功能强大且广泛使用的跨平台 C++ 应用程序框架,适用于图形用户界面(GUI)和嵌入式系统的开发。在医疗设备领域,上位机通常用于数据采集、设备控制、实时监控以及数据分析等任务。通过串口、以太网或 USB 等通信方式,Qt 可以实现与下位机的高效交互,从而构建稳定可靠的医疗设备控制系统[^1]。 #### 通信接口设计 医疗设备的上位机程序通常需要与下位机进行稳定的通信。Qt 提供了 `QSerialPort` 模块来支持串口通信,适用于大多数医疗设备的数据传输需求。以下是一个简单的串口通信示例: ```cpp #include <QSerialPort> #include <QSerialPortInfo> QSerialPort serial; serial.setPortName("COM1"); serial.setBaudRate(QSerialPort::Baud9600); serial.setDataBits(QSerialPort::Data8); serial.setParity(QSerialPort::NoParity); serial.setStopBits(QSerialPort::OneStop); serial.setFlowControl(QSerialPort::NoFlowControl); if (serial.open(QIODevice::ReadWrite)) { QObject::connect(&serial, &QSerialPort::readyRead, [&]() { QByteArray data = serial.readAll(); // 处理接收到的数据 }); } ``` 此外,对于基于 TCP/IP 的网络通信,可以使用 `QTcpSocket` 或 `QUdpSocket` 实现远程数据传输和设备控制[^5]。 #### 数据处理与可视化 医疗设备的上位机程序通常涉及大量数据的采集与分析。Qt 提供了丰富的类库支持数据处理,如 `QVector` 和 `QMap` 用于存储和管理传感器数据,`QSqlDatabase` 支持与 SQLite、MySQL 等数据库交互,便于长期数据存储和查询[^5]。 Qt 还提供了 `QChart` 模块用于数据可视化,可轻松绘制波形图、趋势图和报警曲线。例如,使用 `QLineSeries` 绘制心率变化曲线: ```cpp #include <QtCharts/QChartView> #include <QtCharts/QLineSeries> QtCharts::QLineSeries *series = new QtCharts::QLineSeries(); series->append(0, 60); series->append(1, 62); series->append(2, 58); series->append(3, 65); QtCharts::QChart *chart = new QtCharts::QChart(); chart->legend()->hide(); chart->addSeries(series); chart->createDefaultAxes(); chart->setTitle("Heart Rate Trend"); QtCharts::QChartView *chartView = new QtCharts::QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); ``` #### 用户界面设计 Qt 的布局管理系统(如 `QVBoxLayout`、`QHBoxLayout` 和 `QGridLayout`)可以灵活地组织控件,使界面适应不同分辨率和窗口大小。以下是一个基本的垂直布局示例: ```cpp QWidget *window = new QWidget; QVBoxLayout *layout = new QVBoxLayout; QPushButton *button1 = new QPushButton("Start"); QPushButton *button2 = new QPushButton("Stop"); QPushButton *button3 = new QPushButton("Settings"); layout->addWidget(button1); layout->addWidget(button2); layout->addWidget(button3); window->setLayout(layout); window->show(); ``` 此外,Qt Designer 工具可用于快速构建 UI 原型,并将 `.ui` 文件自动转换为 C++ 代码,提高开发效率[^4]。 #### 多线程与并发处理 为了提高性能并避免主线程阻塞,医疗设备上位机程序通常采用多线程机制。Qt 提供了 `QThread` 和 `QtConcurrent` 等模块,便于实现后台数据采集与前台 UI 更新分离。例如,使用 `QtConcurrent::run` 执行异步任务: ```cpp #include <QtConcurrent/QtConcurrentRun> void fetchData() { // 模拟耗时操作 QThread::sleep(2); qDebug() << "Data fetched"; } QtConcurrent::run(fetchData); ``` 同时,应结合信号与槽机制实现线程间通信,确保数据同步与界面更新的安全性[^5]。 #### 日志与异常处理 医疗设备对系统稳定性要求极高,因此完善的日志记录和异常处理机制是必不可少的。Qt 提供了 `qInstallMessageHandler` 函数用于自定义日志输出,可将调试信息写入文件或发送至服务器。例如: ```cpp void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QFile file("app.log"); if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) return; QTextStream stream(&file); stream << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz") << " "; switch (type) { case QtDebugMsg: stream << "Debug: "; break; case QtInfoMsg: stream << "Info: "; break; case QtWarningMsg: stream << "Warning: "; break; case QtCriticalMsg: stream << "Critical: "; break; case QtFatalMsg: stream << "Fatal: "; break; } stream << msg << " (" << context.file << ":" << context.line << ")" << endl; file.flush(); } qInstallMessageHandler(customMessageHandler); ``` #### 打包与部署 完成开发后,需将应用程序打包以便在目标设备上运行。Qt 提供了 `windeployqt`(Windows)、`macdeployqt`(macOS)等工具自动收集依赖库。此外,可使用 Inno Setup、NSIS 或 Qt Installer Framework 创建安装包,确保最终用户无需额外配置即可运行程序[^3]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

whik1194

如果对你有帮助,欢迎打赏。谢谢

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

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

打赏作者

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

抵扣说明:

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

余额充值