仿写一个串口调试exe(二):创建串口类(同步收发部分),创建接口类,写UI文件测试接口

18 篇文章 0 订阅

a.基础的底层串口类:SimpleSerialPort


下面看的读写功能:异步读写

同步读写:
1.需要用到锁机制QMutexLocker
QMutexLocker创建时将传入的QMutex锁定,释放时将传入的QMutex解锁
2.用到时间循环类QEventLoop
exec()启动该事件的本地循环,一直循环
quit()终止该事件的循环

#include <QMetaEnum>
#include <QMutex>
#include <QThread>
#include <QEventLoop>
//同步写入数据,整个处理过程顺序执行,当各个过程都执行完毕,并返回结果,是所有的操作都做完,才返回给用户结果
	QByteArray writeAndRead(QString data, bool* ok = nullptr, QByteArray endflag = "");
	QByteArray writeAndRead(QByteArray data, bool* ok = nullptr, QByteArray endflag = "");
	

QByteArray SimpleSerialPort::writeAndRead(QString data, bool* ok, QByteArray endflag)
{
    return writeAndRead(data.toLatin1(), ok, endflag);
}

QByteArray SimpleSerialPort::writeAndRead(QByteArray data, bool* ok, QByteArray endflag)
{
    if (!isConnected()) {
        if (ok) {
            *ok = false;
        }
        return QByteArray();
    }

    //加锁
    //QMutexLocker创建时将传入的QMutex锁定,释放时将传入的QMutex解锁
    QMutexLocker locker(&m_lock);
    disconnect(m_com, SIGNAL(readyRead()), this, SLOT(readyData()));

	//这里还可加时钟,控制超时时间(文章下面有介绍)
    QEventLoop loop;    //Qt中的事件循环类
    connect(m_com, SIGNAL(readyRead()), &loop, SLOT(quit()));		//	有数据待读   quit()终止该事件的本地循环
    int writeSize = m_com->write(data);
    m_com->flush();
    if (writeSize != data.size()) {
    	//记录错误
    	qDebug()<<QSC("写数据错误");
    	//return _changeStateAndRecoverConnect(ok);
    }
    loop.exec();        //exec()启动该事件的本地循环,一直循环
    
    QByteArray recvData = m_com->readAll();
    if (!recvData.endsWith(endflag)) {
        int retry = 3;
        while (retry--)
        {
            QThread::msleep(100);
            recvData += m_com->readAll();
            if (recvData.endsWith(endflag)) {
                break;
            }
        }
        if (!recvData.endsWith(endflag)) {
            //记录错误
            qDebug()<<QSC("读数据错误");
            //return _changeStateAndRecoverConnect(ok);
        }
    }
    return recvData;
    //return _changeStateAndRecoverConnect(ok, true, recvData);
}

如果需要记录是否有错误的话,可以使用函数_changeStateAndRecoverConnect,同时返回数据和是否有错误的信息
(把上面代码注释掉的_changeStateAndRecoverConnect部分取消注释即可)

private:
	QByteArray _changeStateAndRecoverConnect(bool* ok, bool state = false, QByteArray data = QByteArray());

QByteArray SimpleSerialPort::_changeStateAndRecoverConnect(bool* ok, bool state, QByteArray data)
{
    if (ok) {
        *ok = state;
    }
    connect(m_com, SIGNAL(readyRead()), this, SLOT(readyData()), Qt::QueuedConnection);
    return data;
}

还可以加一些检测是否超时的错误在程序中,再把writeAndRead函数进行修改

//.h文件
#include <QTimer>
#include <QDateTime>

//新增接口设置超时时间
void setTimeout(int ms);

private slots:
	//	同步读写超时
	void timerTimeout();
...
int m_timeout = 3000;
bool m_timerTimeout = false;
//.cpp
QByteArray SimpleSerialPort::writeAndRead(QByteArray data, bool* ok, QByteArray endflag)
{
    ...
    //	加锁
    QMutexLocker locker(&m_lock);
    disconnect(m_com, SIGNAL(readyRead()), this, SLOT(readyData()));
	
	 m_timerTimeout = false;
    QTimer timer;
    timer.setSingleShot(true);
    QEventLoop loop;
    connect(m_com, SIGNAL(readyRead()), &loop, SLOT(quit()));		//	有数据待读
    connect(&timer, SIGNAL(timeout()), this, SLOT(timerTimeout()));
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));		//	读数据超时
    QString sendTime = QDateTime::currentDateTime().toString("yyyy MM dd hh:mm:ss.zzz");
    int writeSize = m_com->write(data);
    m_com->flush();
    if (writeSize != data.size()) {
        return _changeStateAndRecoverConnect(ok);
    }
    timer.start(m_timeout);
    loop.exec();
    QString recvTime = QDateTime::currentDateTime().toString("yyyy MM dd hh:mm:ss.zzz");
    if (m_timerTimeout) {
        return _changeStateAndRecoverConnect(ok);
    }
    QByteArray recvData = m_com->readAll();

	...
}

void SimpleSerialPort::timerTimeout()
{
    m_timerTimeout = true;
}

void SimpleSerialPort::setTimeout(int ms)
{
    m_timeout = ms;
}

b.供调用的串口接口类:SerialTest

先导入头文件SimpleSerialPort,在构造函数中实例化来导入的类SimpleSerialPort。

//.h
public:
    SerialTest(QObject* parent = nullptr);
    ~SerialTest();

private:
    SimpleSerialPort* m_serial;
//.cpp
SerialTest::SerialTest(QObject* parent)
    :QObject(parent)
{
    m_serial = new SimpleSerialPort();
}

定义可直接使用的功能接口:

1.查找端口:使用m_serial->availableSerialPorts();

Q_INVOKABLE QString Haat_FindPorts();

QString HaatSerial::Haat_FindPorts()
{
    QStringList portsList = m_serial->availableSerialPorts();
    QString ports = "";
    for (QString portTemp : portsList)
        ports = ports + "," + portTemp;
    return ports;
}

2.连接端口:使用m_serial->openSerialPort(port, m_serialSetting); 在程序中组装成SimpleSerialPort中存储端口的结构体SerialPortSettings

Q_INVOKABLE bool Haat_ConnectSerial(QString port, int baudRate = 9600, int dataBits = 8, QString parity = "None", int stopBits = 1, QString flowControl = "None");


bool SerialTest::Haat_ConnectSerial(QString port, int baudRate, int dataBits, QString parity, int stopBits, QString flowControl)
{
    SerialPortSettings m_serialSetting;
    switch (baudRate)
    {
    case 9600:
        m_serialSetting.baudRate = QSerialPort::Baud9600;
        break;
    case 19200:
        m_serialSetting.baudRate = QSerialPort::Baud19200;
        break;
    case 38400:
        m_serialSetting.baudRate = QSerialPort::Baud38400;
        break;
    case 57600:
        m_serialSetting.baudRate = QSerialPort::Baud57600;
        break;
    case 115200:
        m_serialSetting.baudRate = QSerialPort::Baud115200;
        break;
    default:
        m_serialSetting.baudRate = QSerialPort::Baud115200;
        break;
    }
    m_serialSetting.dataBits = QSerialPort::Data8;
    m_serialSetting.parity = QSerialPort::NoParity;
    m_serialSetting.stopBits = QSerialPort::OneStop;
    m_serialSetting.flowControl = QSerialPort::NoFlowControl;
    bool isOpen = m_serial->openSerialPort(port, m_serialSetting);
    return isOpen;
}

3.断开端口

Q_INVOKABLE void Haat_DisconnectSerial();

void SerialTest::Haat_DisconnectSerial()
{
    m_serial->closeSerialPort();
}

4.收发数据

Q_INVOKABLE QString Haat_SendData(QString data, bool isHex = true);
QString SerialTest::Haat_SendData(QString data, bool isHex)
{
    QByteArray receiveData;
    QString result;
  	//暂时只用QString 类型的,isHex暂时不做转换
    receiveData = m_serial->writeAndRead(data.toLatin1());
    result = QString::fromLatin1(receiveData);
    return result;
}

3.写ui文件测试接口

a.ui界面设置

用到的的控件有:按钮:PushButton 下拉框:ComboBox 单选按钮:RadioButton 输入框:LineEdit 文本显示框:TextEdit

可以用GroupBox先画出基本的位置布局,选好之后如果需要基于最底层进行填充,则点到最底层的空白部分右键,选择布局-》水平或者垂直布局则可以从图一变成图二:
图一:
在这里插入图片描述
图二:
在这里插入图片描述
直接在ui中进行修改,基本界面为:
在这里插入图片描述

b.修改UI设计师类的.h和.cpp,调用功能接口进行测试

(见下一篇)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值