QT 串口上位机
CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(SerialPort VERSION 0.1 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets SerialPort) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets SerialPort) set(PROJECT_SOURCES main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) qt_add_executable(SerialPort MANUAL_FINALIZATION ${PROJECT_SOURCES} ) # Define target properties for Android with Qt 6 as: # set_property(TARGET SerialPort APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR # ${CMAKE_CURRENT_SOURCE_DIR}/android) # For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation else() if(ANDROID) add_library(SerialPort SHARED ${PROJECT_SOURCES} ) # Define properties for Android with Qt 5 after find_package() calls as: # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") else() add_executable(SerialPort ${PROJECT_SOURCES} ) endif() endif() target_link_libraries(SerialPort PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt6::SerialPort) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an # explicit, fixed bundle identifier manually though. if(${QT_VERSION} VERSION_LESS 6.1.0) set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.SerialPort) endif() set_target_properties(SerialPort PROPERTIES ${BUNDLE_ID_OPTION} MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE ) include(GNUInstallDirs) install(TARGETS SerialPort BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) if(QT_VERSION_MAJOR EQUAL 6) qt_finalize_executable(SerialPort) endif()
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QWidget> #include <QSerialPort> #include <QTimer> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QWidget { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void init(); private slots: void on_openPortBtn_released(); void on_sendBtn_released(); void onReadyRead(); void on_openFileBtn_released(); void on_sendFileBtn_released(); void on_hexDisplayChx_toggled(bool checked); void on_timerSendChx_toggled(bool checked); void on_sendStopBtn_released(); private: void displayHex(); void displayText(); Ui::MainWindow *ui; QSerialPort serialPort_; QTimer timer_; }; #endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
mainwindow.cpp
#include "mainwindow.h" #include "./ui_mainwindow.h" #include <QSerialPortInfo> #include <QMessageBox> #include <QFileDialog> #include <QStandardPaths> #include <QFile> MainWindow::MainWindow(QWidget *parent) : QWidget(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); init(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::init() { //设置改变 connect(ui->baudRateCmb,&QComboBox::currentIndexChanged,this,[=] { auto br= ui->baudRateCmb->currentData().value<QSerialPort::BaudRate>(); if(!serialPort_.setBaudRate(br)) { QMessageBox::warning(this,"Setting false","设置波特率失败:"+serialPort_.errorString()); } }); connect(ui->dataBitsCmb,&QComboBox::currentIndexChanged,this,[=] { auto value= ui->baudRateCmb->currentData().value<QSerialPort::DataBits>(); if(!serialPort_.setDataBits(value)) { QMessageBox::warning(this,"Setting false","设置数据位失败:"+serialPort_.errorString()); } }); connect(ui->stopBitsCmb,&QComboBox::currentIndexChanged,this,[=] { auto value= ui->stopBitsCmb->currentData().value<QSerialPort::StopBits>(); if(!serialPort_.setStopBits(value)) { QMessageBox::warning(this,"Setting false","设置停止位失败:"+serialPort_.errorString()); } }); connect(ui->parityCmb,&QComboBox::currentIndexChanged,this,[=] { auto value= ui->parityCmb->currentData().value<QSerialPort::Parity>(); if(!serialPort_.setParity(value)) { QMessageBox::warning(this,"Setting false","设置校验位失败:"+serialPort_.errorString()); } }); //获取所有的可用的串口 auto portsInfo=QSerialPortInfo::availablePorts(); for(auto& info : portsInfo) { qInfo()<<info.description()<<info.portName()<<info.systemLocation(); ui->portsCmb->addItem(info.portName()+":"+info.description(),info.portName()); } //获取标准的波特率 auto baudRates=QSerialPortInfo::standardBaudRates(); for(auto br : baudRates) { ui->baudRateCmb->addItem(QString::number(br),br) ; } ui->baudRateCmb->setCurrentText("115200"); //设置停止位 ui->stopBitsCmb->addItem("1",QSerialPort::OneStop); ui->stopBitsCmb->addItem("1.5",QSerialPort::OneAndHalfStop); ui->stopBitsCmb->addItem("2",QSerialPort::TwoStop); //设置数据位 ui->dataBitsCmb->addItem("5Bit",QSerialPort::Data5); ui->dataBitsCmb->addItem("6Bit",QSerialPort::Data6); ui->dataBitsCmb->addItem("7Bit",QSerialPort::Data7); ui->dataBitsCmb->addItem("8Bit",QSerialPort::Data8); ui->dataBitsCmb->setCurrentText("8Bit"); //设置校验位 ui->parityCmb->addItem( "无校验",QSerialPort::NoParity ); ui->parityCmb->addItem( "偶校验",QSerialPort::EvenParity ); ui->parityCmb->addItem( "奇校验",QSerialPort::OddParity ); ui->parityCmb->addItem( "校验为0",QSerialPort::SpaceParity); ui->parityCmb->addItem( "校验为1",QSerialPort::MarkParity ); connect(&serialPort_,&QSerialPort::readyRead,this,&MainWindow::onReadyRead); timer_.callOnTimeout([=] { this->on_sendBtn_released();//调用发送函数 }); } void MainWindow::on_openPortBtn_released() { //判断串口是否已经打开,如果已经打开点击则关闭串口,并让按钮显示为打开串口 if(serialPort_.isOpen()) { serialPort_.close(); ui->openPortBtn->setText("打开串口"); if(timer_.isActive()) timer_.stop(); return; } //获取串口名 auto portName = ui->portsCmb->currentData().toString(); //获取波特率 auto baudRate = ui->baudRateCmb->currentData().value<QSerialPort::BaudRate>(); //获取数据位 auto dataBits = ui->dataBitsCmb->currentData().value<QSerialPort::DataBits>(); //获取停止位 auto stopBits = ui->stopBitsCmb->currentData().value<QSerialPort::StopBits>(); //获取校验位 auto parity = ui->parityCmb->currentData().value<QSerialPort::Parity>(); //设置串口 serialPort_.setPortName(portName); serialPort_.setBaudRate(baudRate); serialPort_.setDataBits(dataBits); serialPort_.setStopBits(stopBits); serialPort_.setParity(parity); //打开串口 if(!serialPort_.open(QIODevice::ReadWrite)) { QMessageBox::warning(this,"warning",portName+"打开失败:"+serialPort_.errorString()); return; } else { ui->openPortBtn->setText("关闭串口"); } } //发送 void MainWindow::on_sendBtn_released() { auto dataStr = ui->sendEdit->toPlainText() +( ui->sendNewLineChx->isChecked() ?"\r\n":"");//判断是否发送新行 serialPort_.write(dataStr.toLocal8Bit()); } //读取 void MainWindow::onReadyRead() { auto data= serialPort_.readAll(); ui->recvEdit->setPlainText(QString::fromLocal8Bit(data)); } //打开文件 void MainWindow::on_openFileBtn_released() { auto filename = QFileDialog::getOpenFileName(this,"选择文件",QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),"txt(*.txt);;all(*.*)"); if(!filename.isEmpty()) { ui->fileNameEdit->setText(filename); } } //发送文件 void MainWindow::on_sendFileBtn_released() { auto filename=ui->fileNameEdit->text(); QFile file(filename); if(!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(this,"warning",filename+"打开失败:"+file.errorString()); return; } serialPort_.write(file.readAll());//serialPort_.write(QString::fromUtf8(file.readAll()).toLocal8Bit());//非UTF8编码 } //显示16进制 void MainWindow::displayHex() { //先取出数据 auto dataStr=ui->recvEdit->toPlainText(); //转成16进制 auto hexData =dataStr.toLocal8Bit().toHex(' ').toUpper(); //再写回去 ui->recvEdit->setPlainText(hexData); } //显示文本 void MainWindow::displayText() { //先取出数据 auto dataStr =ui->recvEdit->toPlainText(); //转成16进制 auto textData =QString::fromLocal8Bit(dataStr.toLocal8Bit()); //再写回去 ui->recvEdit->setPlainText(textData); } //显示16进制开关 void MainWindow::on_hexDisplayChx_toggled(bool checked) { if(checked) displayHex(); else displayText(); } void MainWindow::on_timerSendChx_toggled(bool checked) { if(checked) { timer_.start(ui->timerPeriodEdit->text().toUInt());//开启定时器 ui->timerPeriodEdit->setEnabled(false); } else { timer_.stop(); ui->timerPeriodEdit->setEnabled(true); } } void MainWindow::on_sendStopBtn_released() { serialPort_.clear(); if(timer_.isActive()) timer_.stop(); }
mainwindow.ui