
1.环境配置
sudo apt-get install build-essential
sudo apt-get install cmake qt5-default qtcreator
sudo apt-get install libqt5serialport5
sudo apt-get install libqt5serialport5-dev
sudo apt remove brltty
2.安装CH340驱动
cd /lib/modules/$(uname -r)/kernel/drivers/usb/serial
sudo rm -rf ch341.ko
下载
http://www.wch.cn/download/CH341SER_LINUX_ZIP.html
解压

uname -r
打开
https://elixir.bootlin.com/linux/v5.8/source/drivers/usb/serial/ch341.c
替换源码
make
sudo cp ch341.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial
cd /lib/modules/$(uname -r)/kernel/drivers/usb/serial
测试
sudo apt install cutecom
sudo cutecom
插拔USB执行dmesg会显示连接信息

3.QT源码
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
customplot_init();
serial_init();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::customplot_init()
{
ui->customplot->clearGraphs();
ui->customplot->addGraph();
ui->customplot->graph(0)->setName("波形显示");
//坐标轴使用时间刻度
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
timeTicker->setTimeFormat("%h:%m:%s");
ui->customplot->xAxis->setTicker(timeTicker);
ui->customplot->xAxis->setLabel("时间");//("时间(T)");
ui->customplot->yAxis->setLabel("电压(V)");
ui->customplot->legend->setVisible(true);
//设置基本坐标轴(左侧Y轴和下方X轴)可拖动、可缩放、曲线可选、legend可选、设置伸缩比例,使所有图例可见
ui->customplot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom| QCP::iSelectAxes |
QCP::iSelectLegend | QCP::iSelectPlottables);
}
void MainWindow::serial_init()
{
//读取串口信息
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
// 自动读取串口号添加到端口portBox中
QSerialPort serial;
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
{
ui->portBox->addItem(info.portName());
serial.close();
}
}
QStringList baudList; //波特率
QStringList parityList; //校验位
QStringList dataBitsList; //数据位
QStringList stopBitsList; //停止位
// 波特率 //波特率默认选择下拉第三项:9600
baudList<<"1200"<<"2400"<<"4800"<<"9600"
<<"14400"<<"19200"<<"38400"<<"56000"
<<"57600"<<"115200";
ui->rateBox->addItems(baudList);
ui->rateBox->setCurrentIndex(3);
// 校验 //校验默认选择无
parityList<<"无"<<"奇"<<"偶";
ui->checkBox->addItems(parityList);
ui->checkBox->setCurrentIndex(0);
// 数据位 //数据位默认选择8位
dataBitsList<<"5"<<"6"<<"7"<<"8";
ui->dataBox->addItems(dataBitsList);
ui->dataBox->setCurrentIndex(3);
// 停止位 //停止位默认选择1位
stopBitsList<<"1"<<"2";
ui->stopBox->addItems(stopBitsList);
ui->stopBox->setCurrentIndex(0);
}
void MainWindow::on_searchBtn_clicked()
{
ui->portBox->clear();
//通过QSerialPortInfo查找可用串口
foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
{ //在portBox中显示可用串口
ui->portBox->addItem(info.portName());
}
}
void MainWindow::on_openBtn_clicked()
{
// 打开串口
if(ui->openBtn->text() == "打开串口")
{
SerialPort = new QSerialPort;
// 设置串口号
SerialPort->setPortName(ui->portBox->currentText());
// 打开串口
if(SerialPort->open(QIODevice::ReadWrite))
{
// 设置波特率
SerialPort->setBaudRate(ui->rateBox->currentText().toInt());
//设置数据位数
switch(ui->dataBox->currentIndex())
{
case 5: SerialPort->setDataBits(QSerialPort::Data5); break;
case 6: SerialPort->setDataBits(QSerialPort::Data6); break;
case 7: SerialPort->setDataBits(QSerialPort::Data7); break;
case 8: SerialPort->setDataBits(QSerialPort::Data8); break;
default: break;
}
// 设置校验位
//SerialPort->setParity(QSerialPort::NoParity);
//设置奇偶校验
switch(ui->checkBox->currentIndex())
{
case 0: SerialPort->setParity(QSerialPort::NoParity); break;
case 1: SerialPort->setParity(QSerialPort::OddParity); break;
case 2: SerialPort->setParity(QSerialPort::EvenParity); break;
default: break;
}
// 设置流控制
SerialPort->setFlowControl(QSerialPort::NoFlowControl);
//设置停止位
switch(ui->stopBox->currentIndex())
{
case 1: SerialPort->setStopBits(QSerialPort::OneStop); break;
case 2: SerialPort->setStopBits(QSerialPort::TwoStop); break;
default: break;
}
}
//打开串口
else
{
QMessageBox::about(NULL, "提示", "串口无法打开\r\n不存在或已被占用");
return;
}
ui->openBtn->setText("关闭串口");
//下拉菜单控件使能
ui->portBox->setEnabled(false);
ui->rateBox->setEnabled(false);
ui->dataBox->setEnabled(false);
ui->checkBox->setEnabled(false);
ui->stopBox->setEnabled(false);
//搜索串口按键使能
ui->searchBtn->setEnabled(false);
//发送按键使能
ui->sendBox->setEnabled(true);
connect(SerialPort,&QSerialPort::readyRead,this,&MainWindow::serial_Read); // 接收数据
}
// 关闭串口
else
{
SerialPort->close();
ui->openBtn->setText("打开串口");
//下拉按键使能
ui->portBox->setEnabled(true);
ui->rateBox->setEnabled(true);
ui->dataBox->setEnabled(true);
ui->checkBox->setEnabled(true);
ui->stopBox->setEnabled(true);
//搜索串口按键使能
ui->searchBtn->setEnabled(true);
//发送按键使能
ui->sendBox->setEnabled(false);
}
}
void MainWindow::serial_Read()
{
QString buffer_1;
//从缓冲区中读取数据
QByteArray buffer = SerialPort->readAll();
if(!buffer.isEmpty())//如果非空说明有数据接收
{ //转换成16进制大写
QString str=buffer.toHex().data();
str=str.toUpper();
//一个16进制占4位,8位为一字节,所以每两位16进制空一格
for(int i=0;i<str.length();i+=2)
{
QString str_1 = str.mid (i,2);
buffer_1 += str_1;
buffer_1 += " ";
}
//读取之前显示数据
QString receive = ui->receiveData->toPlainText();
//清空显示
ui->receiveData->clear();
//重新显示
if(ui->radioButton_3->isChecked()==0){
receive += QString(buffer);
ui->receiveData->append(receive);
}//直接显示
else {
receive += QString(buffer_1);
ui->receiveData->append(receive);
}//16进制显示
}
buffer.clear();
}
void MainWindow::on_sendBox_clicked()
{
QByteArray Data_1;
//获取输入窗口sendData的数据
QString Data = ui->sendData->toPlainText();
if(ui->radioButton->isChecked()) {Data+='\r';Data+='\n';}//插入换行
if(ui->radioButton_2->isChecked()==0) Data_1 = Data.toUtf8();//转换成utf8格式的字节流发送
else Data_1 = QByteArray::fromHex (Data.toLatin1().data());//按十六进制编码发送
// 写入发送缓存区
SerialPort->write(Data_1);
}
void MainWindow::on_pushButton_5_clicked()
{
ui->receiveData->clear();
}
void MainWindow::on_pushButton_4_clicked()
{
ui->sendData->clear();
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#pragma execution_character_set("utf-8")
#include <QMainWindow>
#include <QObject>
#include "qcustomplot.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void customplot_init();
void serial_init();
private slots:
void serial_Read();//串口数据读取显示
void on_searchBtn_clicked();
void on_openBtn_clicked();
void on_pushButton_5_clicked();
void on_pushButton_4_clicked();
void on_sendBox_clicked();
private:
Ui::MainWindow *ui;
QSerialPort *SerialPort;
};
#endif // MAINWINDOW_H
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport serialport
CONFIG += c++17
RC_ICONS = favicon.ico
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
QCustomPlot/qcustomplot.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
QCustomPlot/qcustomplot.h \
mainwindow.h
FORMS += \
mainwindow.ui
INCLUDEPATH += QCustomPlot
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target