Qt学习(开发环境Visual Studio)6.串口助手

📅 发布时间:2026/7/14 18:45:08 👁️ 浏览次数:
Qt学习(开发环境Visual Studio)6.串口助手
本文将使用Qt来做一个串口助手并实现通信。首先了解一下串口助手简单来说串口助手就是电脑和设备之间的翻译官兼搬运工。它的工作原理可以浓缩为三步物理连接靠“伪装”现在电脑没有老式串口全靠USB转串口芯片和驱动在系统里“伪造”出一个虚拟串口如COM3。收发数据靠“拆装”发数据时它把你的文字按字符编码表如ASCII转成数字交给驱动和芯片拆成一个一个的比特位发出去。收数据时过程反过来把收到的比特位拼成字节再恢复成文字。核心前提是“约定”你自己设定的波特率、数据位、停止位这些参数只是为了告诉驱动和硬件该以什么节奏拆装数据。通信双方的这些设置必须完全一致否则就会乱码。目录新建项目ui界面设计属性配置查看Qt助手代码部分新建项目将项目命名为 SerialPortGui点击创建将类的名字改为SerialPort 选择QWidget创建完成从网上下载一个串口助手的程序为了简单起见我们做的串口就保留核心的功能端口、波特率、校验位、数据位、停止位combox打开串口发送按钮(botton)发送区接收区textEdit这几个功能即可。ui界面设计界面如下关于控件的命名看右侧栏。接收区要设置为只读发送按钮选上checkable这样点击后变色用于区分有没有打开。属性配置点击项目 右键-属性-Qt Project Settings勾选串口需要的模块查看Qt助手找到SerialPort类还有一个SerialPortInfoSerialPort类Inherits继承自QIODevice这是QT中所有输入/输出设备的抽象类提供了统一的接口来读写各种设备看一下串口的Public TypesBaudRate 波特率类型是枚举QT里面固定提供了1200、2400、4800等数值其他类似DataBits 数据位Parity 校验位StopBits 停止位FlowControl是否使用流控等是我们需要用到的。这部分是他们的类型来看函数这几个函数用来获取信息比如parityconst 是用来获取当前串口校验位置的查询函数它的返回类型是QSerialPort::Parity枚举类型可能的值QSerialPort::NoParity // 无校验 (0) QSerialPort::EvenParity // 偶校验 (2) QSerialPort::OddParity // 奇校验 (3) QSerialPort::SpaceParity // 空校验 (4) QSerialPort::MarkParity // 标记校验 (5)为了实现串口通信首先要打开串口-获取有效串口Port-设置波特率和校验信息等-编辑发送内容-点击发送这个函数用来获取有用的串口QIODevice类里面有关于读写的部分。代码部分这个项目分成两个部分涉及到界面的一部分实现串口通信的是一部分。所以要新建项再新建一个头文件放结构体#includeQstring struct SerialPortParam { QString spp_port_name COM5; //串口名称 qint32 spp_baud_rate 9600; //波特率 int spp_data_bits 5; //数据位 int spp_parity 0; //校验位 int spp_stop_bits 0; //停止位 };给serialPort.h添加头文件#pragma once #include QtSerialPort/QSerialPort #include QTextStream #include QObject #include Struct.h /* * brief 创建结构体包含串口各个参数 */ class SerialPort : public QSerialPort { Q_OBJECT public: SerialPort(QObject * parent nullptr); ~SerialPort(); public: /* * brief 打开/关闭串口 * param in spp 结构体包含了串口的各个参数 */ bool open_port(const SerialPortParam spp); /* * brief 关闭串口 */ void close_port(); /* * brief 发送数据 * param data 发送的二进制数据 */ void send_data(const QByteArray data); /* * brief 获取可用串口列表 * param out 串口列表 */ QStringList get_vali_port(); signals: /* * brief 接收到数据的信号 * param data 接收的二进制数据 */ void sigDataReceived(const QByteArray data); /* * brief 串口状态变化的信号 * param isOpen 串口是否开启 */ void sigPortStatusChanged(bool isOpen); private slots: /* * brief 读取串口数据 */ void slotReadData(); private: QSerialPort* m_serialPort nullptr; };然后是SerialPort.cpp#include SerialPort.h #include QtSerialPort/QSerialPortInfo // 构造函数初始化串口对象 SerialPort::SerialPort(QObject*parent) { m_serialPort new QSerialPort(this); // 连接串口的readyRead信号到readData槽函数串口有数据可读触发slotReadData connect(m_serialPort, QSerialPort::readyRead, this, SerialPort::slotReadData); } SerialPort::~SerialPort() { } bool SerialPort::open_port(const SerialPortParam spp) { // 如果串口已经打开直接返回true if (m_serialPort-isOpen()) { return true; } // 配置串口参数 m_serialPort-setPortName(spp.spp_port_name);// 设置端口名 m_serialPort-setBaudRate(spp.spp_baud_rate);// 设置波特率 m_serialPort-setDataBits(static_castQSerialPort::DataBits(spp.spp_data_bits));// 设置数据位 m_serialPort-setParity(static_castQSerialPort::Parity(spp.spp_parity)); // 设置校验位 m_serialPort-setStopBits(static_castQSerialPort::StopBits(spp.spp_stop_bits)); // 设置停止位 m_serialPort-setFlowControl(QSerialPort::NoFlowControl);// 禁用流控 bool bRt m_serialPort-open(QIODevice::ReadWrite); return bRt; } void SerialPort::close_port() { if (m_serialPort-isOpen()) { m_serialPort-close(); // 关闭串口 emit sigPortStatusChanged(false); // 发送状态变化信号 } } void SerialPort::send_data(const QByteArray data) { // 检查串口是否打开 if (m_serialPort-isOpen()) { m_serialPort-write(data); // 写入数据 emit get_vali_port(); } } //获取可用串口列表 QStringList SerialPort::get_vali_port() { QStringList ports; foreach(const QSerialPortInfo info, QSerialPortInfo::availablePorts()) { ports info.portName();///将串口名添加到列表 } return ports; //返回系统可用串口的名称列表 } // 读取串口数据 void SerialPort::slotReadData() { QByteArray data m_serialPort-readAll(); // 读取所有可用数据 emit sigDataReceived(data); // 发送数据接收信号 }SerialPortWid.h#pragma once #include SerialPort.h #include ui_SerialPort.h class SerialPortWid : public QWidget { Q_OBJECT public: SerialPortWid(QWidget* parent nullptr); ~SerialPortWid(); private slots: /* * brief 打开/关闭串口按钮点击槽函数 */ void slotOpen(); /* * brief 判断发送区内容是否被用户编辑 * param 发送区的内容 */ void slotTextEdited(const QString text); /** * brief 发送数据按钮点击槽函数 */ void slotSend(); /** * brief 串口状态变化槽函数 * param isOpen 串口是否打开 */ void slotPortStatusChanged(bool isOpen); /** * brief 数据接收槽函数 * param data 接收到的数据 */ void slotReceived(const QByteArray data); private: /** * brief 更新串口参数设置 * 从UI控件读取当前参数并保存 */ void updatePortSettings(); private: Ui::SerialPortWid* ui nullptr; //ui界面指针 SerialPort* m_serialPort nullptr; //串口操作对象 };serialPort.cpp#include SerialPortWid.h #include Struct.h SerialPortWid::SerialPortWid(QWidget* parent) : QWidget(parent) , ui(new Ui::SerialPortWid) , m_serialPort(new SerialPort(this)) { ui-setupUi(this); //为QComboBox的每个选项设置关联的用户数据 ui-m_cbParity-setItemData(0, QSerialPort::NoParity);//校验位 无校验 ui-m_cbParity-setItemData(1, QSerialPort::EvenParity);//偶校验 ui-m_cbParity-setItemData(2, QSerialPort::OddParity);//奇校验 ui-m_cbStopBits-setItemData(0, QSerialPort::OneStop);//停止位1 ui-m_cbStopBits-setItemData(1, QSerialPort::OneAndHalfStop);//停止位1.5 ui-m_cbStopBits-setItemData(2, QSerialPort::TwoStop);//停止位2 // 连接信号槽 connect(ui-m_pbOpenClose, QPushButton::clicked, this, SerialPortWid::slotOpen);//打开串口 connect(m_serialPort, SerialPort::sigPortStatusChanged, this, SerialPortWid::slotPortStatusChanged);//更新UI connect(m_serialPort, SerialPort::sigDataReceived, this, SerialPortWid::slotReceived);//显示数据 connect(ui-m_teSend, QLineEdit::textEdited, this, SerialPortWid::slotTextEdited);//判断文本是否编辑 connect(ui-m_pbSend,QPushButton::clicked, this, SerialPortWid::slotSend);//发送数据 // 扫描可用串口 QStringList ports m_serialPort-get_vali_port(); ui-m_cbPort-clear(); ui-m_cbPort-addItems(ports); if (!ports.isEmpty()) { ui-m_cbPort-setCurrentIndex(0); } } SerialPortWid::~SerialPortWid() { } //打开/关闭串口按钮点击事件 void SerialPortWid::slotOpen() { if (!ui-m_pbOpenClose-isChecked()) { m_serialPort-close_port(); } else { updatePortSettings(); // 从UI更新串口参数 SerialPortParam spp; // 创建参数结构体 // 从UI控件读取参数 spp.spp_port_name ui-m_cbPort-currentText();//端口名 spp.spp_baud_rate ui-m_cbBaudRate-currentText().toInt();// 波特率 bool ok; int dataBits ui-m_cbDataBits-currentText().toInt(ok); if (ok) { spp.spp_data_bits static_castQSerialPort::DataBits(dataBits); } spp.spp_data_bits static_castQSerialPort::DataBits(ui-m_cbDataBits-currentText().toInt()); // 数据位 spp.spp_parity static_castQSerialPort::Parity(ui-m_cbParity-currentData().toInt());// 校验位 spp.spp_stop_bits static_castQSerialPort::StopBits(ui-m_cbStopBits-currentData().toInt()); // 停止位 m_serialPort-open_port(spp); // 打开串口 } } void SerialPortWid::slotTextEdited(const QString text) { ui-m_pbSend-setEnabled(!text.isEmpty()); } void SerialPortWid::slotSend() { QString text ui-m_teSend-text(); // 获取发送框文本 if (!text.isEmpty()) { m_serialPort-send_data(text.toUtf8()); } } void SerialPortWid::slotPortStatusChanged(bool isOpen) { Q_UNUSED(isOpen); // 避免未使用参数警告 } void SerialPortWid::slotReceived(const QByteArray data) { ui-m_teRecevie-append(QString::fromUtf8(data)); } void SerialPortWid::updatePortSettings() { SerialPortParam param; // 设置端口名称 param.spp_port_name ui-m_cbPort-currentText(); // 设置波特率 QString baudRateStr ui-m_cbBaudRate-currentText(); param.spp_baud_rate baudRateStr.toInt(); // 设置数据位使用itemData获取关联的枚举值 param.spp_data_bits static_castQSerialPort::DataBits( ui-m_cbDataBits-currentData().toInt()); // 设置校验位使用itemData获取关联的枚举值 param.spp_parity static_castQSerialPort::Parity( ui-m_cbParity-currentData().toInt()); // 设置停止位使用itemData获取关联的枚举值 param.spp_stop_bits static_castQSerialPort::StopBits( ui-m_cbStopBits-currentData().toInt()); }可以正常通信了~