QT上位机:串口调试助手

前言

  上位机的简单编写可以帮我们测试并完善平台,QT作为一款跨平台的GUI开发框架,提供了非常丰富的常用串口api。本文先从最简单的串口调试助手开始,编写平台软件的串口控制界面

工程配置

  QT 串口通信基于QT的QSerialPort类,先在项目文件pro中添加QT += serialport。
  避免默认的widget类和ui命名,将串口部分的ui命名为ui_serial,类命名为serial

界面设置

  在UI界面可以直接搭建我们想要的界面显示方案,并自动生成相应代码添加头文件,用起来还是非常方便的,注意不要和代码里手动添加的混淆就好了
  需要配置的可以选择QComboBox,添加常用的配置项,比如串口号,波特率,数据校验停止位等
  添加led指示灯QLabel,可以用来美化界面
  点击选中的可以选择QRadioButton,用以单选,直观的给以感受
  收发的界面选择文本框QPlainTextEdit,可以多行显示
  手动加的短文本框可以用QLineEdit,可以单行显示
  其余的用最基础的pushbutton就可以了
  为了界面不会被放大缩小导致排版混乱,可以添加弹簧或者直接写死窗口大小
  设计完成后,会保存为对应名称比如serial.ui
在这里插入图片描述

  构造函数里需要将有交互的部分connect起来,将界面按键的初始值做设置
  我们可以通过继承QSerialPort类,也可以直接继承Qwidget类,在里面申明Qserialport

class serial : public QWidget
{Q_OBJECTpublic:explicit serial(QWidget *parent = 0);QSerialPort *serialPort;~serial();
private slots:void serialPortReadyRead_Slot();void on_OpenBt_clicked();void on_SendBt_clicked();void on_SaveBt_clicked();void on_ClearBt_clicked();void on_pushButton_clicked();private:QPushButton *m_button;void LED(bool changeColor); //串口连接指示灯void closeEvent(QCloseEvent *event);  /***关闭***/void on_comStatus(QString name, bool flag);Ui::serial *ui_serial;};
serial::serial(QWidget *parent) :QWidget(parent),ui_serial(new Ui::serial)
{ui_serial->setupUi(this);setWindowTitle("串口控制界面-HX");this->setFixedSize(980, 600); // 固定窗口的大小/***************定义接收格式数据按钮********************/QButtonGroup *btnGroupRev=new QButtonGroup(this);btnGroupRev->addButton(ui_serial->ASCII_Receive_Box,0); // 将给定的按钮添加到按钮组btnGroupRev->addButton(ui_serial->HEX_Receive_Box,1);ui_serial->ASCII_Receive_Box->setChecked(true); // 设置默认模式/***************定义发送格式数据按钮********************/QButtonGroup *btnGroupSend=new QButtonGroup(this);btnGroupSend->addButton(ui_serial->ASCII_Send_Box,0); // 将给定的按钮添加到按钮组btnGroupSend->addButton(ui_serial->HEX_Send_Box,1);ui_serial->ASCII_Send_Box->setChecked(true);  // 设置默认模式serialPort = new QSerialPort(this);connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot()));/***************串口热插拔********************/ComChange::getInstance()->setHWND((HWND)this->winId());connect(ComChange::getInstance(), &ComChange::comStatus, this, &serial::on_comStatus);QStringList strName = ComChange::getAvailablePort();              // 获取所有可用串口ui_serial->SerialCb->addItems(strName);/*连接rtsp界面*/
//    m_button = findChild<QPushButton*>("pushButton_3"); // 查找已有的pushButton3对象
//    qDebug()<<"m_button is :"<<m_button;
//    connect(this, &serial::buttonClicked_ctrl_left, this, &serial::on_pushButton_3_clicked);
// 连接信号与槽//}

  考虑到热插拔的问题封装getAvailablePort获取当前可用串口

ComChange* ComChange::m_comChange = nullptr;
ComChange *ComChange::getInstance()
{if(m_comChange == nullptr){static QMutex mutex;         //实例互斥锁。QMutexLocker locker(&mutex); //加互斥锁。if(m_comChange == nullptr){m_comChange = new ComChange();}}return m_comChange;}/*** @brief   获取系统中所有可用的串口名* @return*/
QStringList ComChange::getAvailablePort()
{QStringList strName;foreach(const QSerialPortInfo& info, QSerialPortInfo::availablePorts()){QSerialPort port(info);if(port.open(QIODevice::ReadWrite)){strName << info.portName();port.close();}}return strName;
}

串口的热插拔

/*函   数:on_comStatus描   述:串口热插拔操作。有comchange的h文件、cpp文件和该函数,才能支持串口热插拔操作,缺一不可。移植请注意。输   入:串口名称:name, 连接标志:flag输   出:无
*/
void serial::on_comStatus(QString name, bool flag)
{if(flag)  ui_serial->SerialCb->addItem(name); // 串口插入时自动添加串口名else{ui_serial->SerialCb->removeItem(ui_serial->SerialCb->findText(name)); // 串口拔出时自动移除串口名LED(false); //红色LED 表示关闭串口serialPort->close(); //关闭串口ui_serial->OpenBt->setText("打开串口");}}

串口的初始化

  在点击打开串口的时候做初始化,使用open(QIODevice::ReadWrite)用ReadWrite 的模式尝试打开串口,打开成功后设置串口通信的波特率,校验方式等配置。(打开方式有多种,只读(r/o)、只写(w/o)或读写(r/w)模式)
直接使用serialPort的相关API
  setPortName将当前串口的名字设置为系统可用串口的名字
  setBaudRate设置波特率
  setDataBits设置数据位
  setStopBits设置停止位
  setParity设置校验位
  close关闭串口
  注意:串口始终以独占访问方式打开(即没有其他进程或线程可以访问已打开的串口)。

/*函   数:on_OpenBt_clicked描   述:打开串口时初始化串口输   入:无输   出:无
*/
void serial::on_OpenBt_clicked()
{if(ui_serial->OpenBt->text()=="打开串口"){serialPort->setPortName(ui_serial->SerialCb->currentText()); // 将当前串口的名字设置为系统可用串口的名字qint32 baudrate = ui_serial->BaundCb->currentText().toInt(); // 获取期望的波特率serialPort->setBaudRate(baudrate);  // 设置波特率//设置数据位switch(ui_serial->DataCb->currentText().toInt()){case 8:serialPort->setDataBits(QSerialPort::Data8); break;case 7:serialPort->setDataBits(QSerialPort::Data7); break;case 6:serialPort->setDataBits(QSerialPort::Data6); break;case 5:serialPort->setDataBits(QSerialPort::Data5); break;}//设置停止位if(ui_serial->StopCb->currentText() == "1"){serialPort->setStopBits(QSerialPort::OneStop);}else if(ui_serial->StopCb->currentText() == "1.5"){serialPort->setStopBits(QSerialPort::OneAndHalfStop);}else if(ui_serial->StopCb->currentText() == "2"){serialPort->setStopBits(QSerialPort::TwoStop);}//设置校验位if(ui_serial->CheckCb->currentText() == "None"){serialPort->setParity(QSerialPort::NoParity);}else if(ui_serial->CheckCb->currentText() == "Even"){serialPort->setParity(QSerialPort::EvenParity);}else if(ui_serial->CheckCb->currentText() == "Odd"){serialPort->setParity(QSerialPort::OddParity);}LED(true); //绿色LED 表示打开串口//串口连接失败提示if(serialPort->open(QIODevice::ReadWrite) == false){QMessageBox::critical(this, "提示", "串口连接失败");LED(false); //红色LED 表示关闭串口}ui_serial->OpenBt->setText("关闭串口");}else{LED(false); //红色LED 表示关闭串口serialPort->close(); //关闭串口ui_serial->OpenBt->setText("打开串口");}
}

串口的收发

  根据hex和ASCII在收发时做判断serialPort->readAll();可以接收所有信息,serialPort->write(SendTextByte); /可以通过串口将数据发送出去

/*函   数:serialPortReadyRead_Slot描   述:上位机接收数据输   入:无输   出:无
*/
void serial::serialPortReadyRead_Slot()
{QByteArray buf = serialPort->readAll(); //从串口读取信息if(ui_serial->ASCII_Receive_Box->isChecked()) //如果设置接收ASCII{ui_serial->ReceiveEdit->insertPlainText(QString::fromLocal8Bit(buf)); // 对串口接收的数据进行编码}else if(ui_serial->HEX_Receive_Box->isChecked()) //如果设置接收HEX{QDataStream out(&buf, QIODevice::ReadWrite); //读取数据while(!out.atEnd()) //读取是否完成{qint8 outChar = 0;out >> outChar;QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')); //转换16进制ui_serial->ReceiveEdit->insertPlainText(str+" "); //每显示一次后面加一个空格}}
}/*函   数:on_SendBt_clicked描   述:上位机发送数据输   入:无输   出:无
*/
void serial::on_SendBt_clicked()
{QString sendstr=ui_serial->SendEdit->toPlainText();  //获取将要发送数据if(ui_serial->ASCII_Send_Box->isChecked())  // 如果发送ASCII模式{QByteArray SendTextByte = sendstr.toLocal8Bit(); //将发送的数据转换格式serialPort->write(SendTextByte); // 通过串口将数据发送出去}else if(ui_serial->HEX_Send_Box->isChecked())  // 如果发送HEX{QByteArray SendTextByte = QByteArray::fromHex(sendstr.toLatin1());  // 转换数据格式serialPort->write(SendTextByte); // 通过串口将数据发送出去}
}

接收区清除

  为了直观的读取接收区数据,也需要增加清除当前数据的功能

/*函   数:on_ClearBt_clicked描   述:清空接收区的数据输   入:无输   出:无
*/
void serial::on_ClearBt_clicked()
{ui_serial->ReceiveEdit->clear();
}

接收数据的保存

  数据量大的时候经常需要保存接收数据的log,所以存log的功能也是必不可少的
file.open(QFile::WriteOnly | QFile::Text)可以将文本数据框取出并按行排列

/*函   数:on_SaveBt_clicked描   述:以TXT格式保存接收区数据输   入:无输   出:无
*/
void serial::on_SaveBt_clicked()
{QString textFile = QFileDialog::getSaveFileName(this,tr("Save txt"),"",tr("text (*.txt)")); //选择路径//将文本框数据取出并按行排列QFile file(textFile);//文件命名if (!file.open(QFile::WriteOnly | QFile::Text))     //检测文件是否打开{QMessageBox::information(this, "Error Message", "Please Select a Text File!");return;}QTextStream out(&file);                 //分行写入文件out << ui_serial->ReceiveEdit->toPlainText();
}

指示灯的使用

  为了美化界面,直观显示串口是否正常连接,可以加个指示灯,设置绿色表示开红色表示关

/*函   数:closeEvent描   述:关闭窗口时若未关闭串口,则要关闭串口输   入:无输   出:无
*/
void serial::closeEvent(QCloseEvent *event)
{if(serialPort->isOpen())   // 串口处于打开状态{LED(false); //红色LED 表示关闭串口serialPort->close();  // 串口关闭event->accept();  // 界面关闭}
}/*函   数:LED描   述:串口指示灯输   入:bool changeColor输   出:无
*/
void  serial::LED(bool changeColor)
{if(changeColor == true){// 显示绿色ui_serial->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(0, 229, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:9px;");}else{// 显示红色ui_serial->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(255, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:9px;");}
}

窗口退出

  为了避免退出的时候占用串口,关闭窗口的时候需要关闭串口

/*函   数:closeEvent描   述:关闭窗口时若未关闭串口,则要关闭串口输   入:无输   出:无
*/
void serial::closeEvent(QCloseEvent *event)
{if(serialPort->isOpen())   // 串口处于打开状态{LED(false); //红色LED 表示关闭串口serialPort->close();  // 串口关闭event->accept();  // 界面关闭}
}

具体功能

  剩下的就是根据协议规定点击pushbutton发送相应的内容了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/457034.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AR人脸106240点位检测解决方案

美摄科技针对企业需求推出了AR人脸106/240点位检测解决方案&#xff0c;为企业提供高效、精准的人脸识别服务&#xff0c;采用先进的人脸识别算法和机器学习技术&#xff0c;通过高精度、高速度的检测设备&#xff0c;对人脸进行快速、准确地定位和识别。该方案适用于各种应用场…

上位机图像处理和嵌入式模块部署(统计函数执行时间)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 和pc上位机相比较&#xff0c;嵌入式设备的计算资源很多时候都是不足的。但是&#xff0c;嵌入式设备胜在稳定性和成本上面&#xff0c;这方面又是…

一些基础函数

链表 ListNode* pnew ListNode(0,head); 栈和队列 stack—— stack<int> st; st.push(1); st.push(2); // st: 1 2 st.top(); // 2 st.size(); // 2 st.pop(); // st: 1 st.empty(); // false queue—— queue<int> que; que.push(1); que.push(2); // que: …

python 动态数据 展示 ,数据是由51单片机发送过来的,温度传感器。

import tkinter as tk import randomimport seriallis[] for i in range(50):lis.append(i1) # 打开串行端口 ser serial.Serial(COM3, 9600) # 9600为波特率&#xff0c;根据实际情况进行调整# 初始化数据 lis [random.randint(15, 35) for _ in range(50)]def update_data…

golang 引入swagger(iris、gin)

golang 引入swagger&#xff08;iris、gin&#xff09; 在开发过程中&#xff0c;我们不免需要调试我们的接口&#xff0c;但是有些接口测试工具无法根据我们的接口变化而动态变化。文档和代码是分离的。总是出现文档和代码不同步的情况。这个时候就可以在我们项目中引入swagge…

[自然语言处理|NLP] 文本分类与情感分析,数据预处理流程,包括了同义词替换和拼写纠正,以及使用NLTK库和TextBlob库进行标记化和情感分析(附代码)

[自然语言处理|NLP] 文本分类与情感分析,数据预处理流程,包括了同义词替换和拼写纠正,以及使用NLTK库和TextBlob库进行标记化和情感分析(附代码)。 自然语言处理(Natural Language Processing,简称NLP)是人工智能领域的一个重要分支,涉及了处理和理解人类语言的技术…

网工内推 | 上市公司运维岗,红帽认证优先,带薪年假,节日福利

01 捷科智诚 招聘岗位&#xff1a;配置管理岗-运维 职责描述&#xff1a; 1.负责日常配置管理平台的维护及优化&#xff0c;包括权限管理、基线管理、版本管理、发布管理、变更管理等&#xff1b; 2.负责维护各个管理平台的用户管理、权限管理、项目初始化等工作&#xff1b; …

睿尔曼超轻量仿人机械臂-- RM65-B手眼标定使用说明

一、前言 机器人的视觉系统分为固定场景视觉系统和运动的「手-眼」视觉系统。相机与机器人手臂末端&#xff0c;构成手眼视觉系统。根据相机在机器人安装位置的不同&#xff0c;手眼视觉系统分为Eye-in-Hand系统&#xff08;眼在手上&#xff09;和Eye-to-Hand系统&#xff08…

【芯片设计- RTL 数字逻辑设计入门 10 -- 奇偶校验实现】

文章目录 奇偶校验单目运算符&#xff08;|,^,&&#xff09;verilog codeverilog codetestbench code 问题总结 奇偶校验 现在需要对输入的32位数据进行奇偶校验,根据sel输出校验结果。 实际上这里做的是奇偶检测&#xff0c;如果是奇数个 1 则结果为 1&#xff0c;使用…

代码随想录算法训练营第四十五天(动态规划篇)|01背包

01背包理论基础 学习资料&#xff1a;代码随想录 (programmercarl.com) 相关链接&#xff1a;题目页面 (kamacoder.com) 背包题目分类 01背包定义 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次…

uniCloud ---- schema2code

目录 schema2code有两种方式 label属性 component属性 group属性 应用 DB Schema里有大量的信息&#xff0c;其实有了这些信息&#xff0c;前端将无需自己开发表单维护界面&#xff0c;uniCloud可以自动生成新增、修改、列表、详情的前端页面&#xff0c;以及admin端的列…

在openSUSE-Leap-15.5-DVD-x86_64中使用deepin-wine-8.16再使用微信3.9.7.29

在openSUSE-Leap-15.5-DVD-x86_64中使用deepin-wine-8.16再使用微信3.9.7.29 《在openSUSE-Leap-15.5-DVD-x86_64中使用deepin-wine-6.0.0.62再使用微信3.9.5》 https://blog.csdn.net/weixin_42145772/article/details/135074804?spm1001.2014.3001.5501 按照上面文章的方法…