Qt开发串口

首先,在工程文件里面,

QT += serialport

在头文件里面,

#include <QSerialPort>

1、配置打开串口

QSerialPort* myserial = new QSerialPort();
this->myserial->setPortName("COM1");//待打开的串口号
this->myserial->setBaudRate(9600,QSerialPort::AllDirections);//设置波特率;QSerialPort::AllDirections:双工
this->myserial->setDataBits(QSerialPort::Data8);//数据位
this->myserial->setParity(QSerialPort::NoParity);//校验位
this->myserial->setStopBits(QSerialPort::OneStop);//停止位
this->myserial->setFlowControl(QSerialPort::NoFlowControl);//流控制
this->myserial->open(QIODevice::ReadWrite);//打开串口

 

 2、发送数据

char test[5] = {0x01,0x02,0x03,0x04,0x05};

myserial.write(test);//发送

3、接收数据

定义一个函数作为槽函数,当接收缓冲区有数据的时候回调此函数。

void ReadBuf()
{
  QByteArray dataArray;
  dataArray = myserial->readAll();//读取数据
  if(!dataArray.isEmpty())
  {
    QString str;
    str = dataArray.toHex();//把数据直接转化为16进制的字符串形式
    ui->textEdit->setText(str);
  }
}

 

 此外,在打开串口函数里面关联信号与槽。已知,当接收缓冲区有数据的时候,串口对象会发送readyRead信号。

QObject::connect(myserial,&QSerialPort::readyRead,this,&MainWindow::ReadBuf);

4、关闭串口

this->myserial->close();

备注一、自动获取可用串口号,并设置在QComboBox中

1、需要包含头文件

#include <QSettings>

#include <qt_windows.h>

2、自定义函数

QString getcomm(int index, QString keyorvalue)
{
   HKEY hKey;
    wchar_t keyname[256]; //键名数组
    char keyvalue[256];  //键值数组
    DWORD keysize,type,valuesize;
    int indexnum;
    QString commresult;
    if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ, &hKey) != 0)
    {
        QString error="Cannot open regedit!";
        return error;
    }
    QString keymessage;//键名
    QString message;
    QString valuemessage;//键值
    indexnum = index;//要读取键值的索引号
    keysize = sizeof(keyname);
    valuesize = sizeof(keyvalue);
    if (RegEnumValue(hKey, indexnum, keyname, &keysize, 0, &type, (BYTE*)keyvalue, &valuesize) == 0)
    {
        for (int i=0; i<(int)keysize; i++)
        {
            message = keyname[i];
            keymessage.append(message);
        }
        for (int j=0; j<(int)valuesize; j++)
        {
            if (keyvalue[j] != 0x00)
                valuemessage.append(keyvalue[j]);
        }
        if (keyorvalue == "key")
            commresult = keymessage;
        if (keyorvalue == "value")
            commresult=valuemessage;
    }
    else
        commresult = "nokey";
    RegCloseKey(hKey);//关闭注册表
    return commresult;
}

 

3、将可用串口放在QComboBox里面

void MainWindow::InitInterface()
{
    QString path = "HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM";
    QSettings *settings = new QSettings(path, QSettings::NativeFormat);
    QStringList key = settings->allKeys();
    QStringList comlist;
    comlist.clear();
    /* 取串口名 */
    for (int i=0; i<key.size(); i++)
        comlist << getcomm(i, "value");
    ui->comboBox->addItems(comlist);
}

 


PS:
1、波特率9600意思是每秒最多传输9600/8=1200个字节;
2、如何解决粘包:(以传输ascii为例)
1)、接收数据,如果数据长度刚好为协议那么长,则直接解析
2)、如果长度不正确就把此包追加到本地变量中,然后判断根据报文头的位置把本地变量去掉报文头前面的数据(QString::mid)
3)、判断长度是否足够(并且本地变量的头是协议头),如果足够则取本地变量前n个数据进行解析,并将本地变量去掉这个包;如果不是协议头则清空此变量,再次进行循环

PS:
1、开发流程

 

2、如果编译器是MSVC,可能会报错:

无法解析的外部符号:regclosekey

 

 3.同步读取串口

### 头文件

```
#include "InsScpi.h"
#include <QObject>
#include <QSerialPort>


class TestSerial : public QObject
{
    Q_OBJECT
public:
    explicit TestSerial(QObject *parent = nullptr);

    //打开设备
    bool    openDevice(const QString &portName);

    //关闭设备
    void    closeDevice();

    //发送数据
    bool    write(const char* cmd, qint64 maxSize);

    //-- 获取温度 
    //-- 返回字符串格式:
    //-- "22.3408    22.7402    24.3184    24.6043"
    QString getTemp(bool& ok, int msec = 500);

signals:
    void    sig_finishReadSerial();     //完成串口读取信号

private:
    void    init();                     //初始化函数

private:
    QSerialPort*    m_serialPort    = nullptr;  //串口
    QString         m_portName      = "COM1";   //串口号

    //串口描述信息
    using QtSP = QSerialPort;
    QtSP::BaudRate   m_baudRate  = QtSP::Baud115200;    //波特率
    QtSP::DataBits   m_dataBits  = QtSP::Data8;         //数据位长度
    QtSP::Parity     m_parity    = QtSP::NoParity;      //校验位
    QtSP::StopBits   m_stopBits  = QtSP::OneStop;       //停止位
};
```

### 实现

```

#include <QDebug>
#include <QEventLoop>
#include <QTimer>

TestSerial::TestSerial( QObject *parent)
    : QObject{parent}
{
    (void)init();
}

void TestSerial::init()
{
    //[1] 实例化串口对象
    if (!m_serialPort)
    {
        m_serialPort = new QSerialPort();
    }
}

bool TestSerial::openDevice(const QString &portName)
{
    //[1] 判断串口对象是否实例化
    if (!m_serialPort)
    {
        qDebug() << "serial obj is null";
        return false;
    }

    //[2] 判断串口是否已经打开
    if (m_serialPort->isOpen())
    {
        qDebug() << "device is already open";
        return false;
    }

    //[3] 设置串口信息
    m_portName = portName;
    m_serialPort->setPortName(m_portName);
    m_serialPort->setBaudRate(m_baudRate, QSerialPort::AllDirections);
    m_serialPort->setDataBits(m_dataBits);
    m_serialPort->setParity(m_parity);
    m_serialPort->setStopBits(m_stopBits);
    m_serialPort->setFlowControl(QSerialPort::NoFlowControl);

    //[4] 打开串口
    return m_serialPort->open(QIODevice::ReadWrite);
}

void TestSerial::closeDevice()
{
    //[1] 判断串口对象是否实例化
    if (!m_serialPort)
    {
        qDebug() << "serial obj is null";
        return;
    }

    //[2] 关闭串口
    m_serialPort->close();
}

bool TestSerial::write(const char *cmd, qint64 maxSize)
{
    //[1] 判断串口对象是否实例化
    if (!m_serialPort)
    {
        qDebug() << "serial obj is null";
        return false;
    }

    //[2] 判断串口是否打开
    if (!m_serialPort->isOpen())
    {
        qDebug() << "serial is not open";
        return false;
    }

    //[3] 发送数据
    if(maxSize != m_serialPort->write(cmd, maxSize))
    {
        qDebug() << "send serial data failed";
        return false;
    }
    return true;
}

//-- 获取温度 
//-- 返回字符串格式:
//-- "22.3408    22.7402    24.3184    24.6043"
QString TestSerial::getTemp(bool& ok, int msec)
{
    static QString ret;
    ret.clear();
    if (!m_serialPort){
        qDebug() << "serial obj is null";
        return "";
    }
    QEventLoop loop;
    QObject::connect(this, &TestSerial::sig_finishReadSerial, &loop, &QEventLoop::quit);
    QTimer::singleShot(msec, this, [&]{ emit sig_finishReadSerial(); });

    QByteArray cmdBa = "getTemp()";
    m_serialPort->clear();
    if(0 != cmdBa.size()) {
        if(cmdBa.size() == m_serialPort->write(cmdBa)) ok = true;
        else ok = false;
    }
    auto async = QObject::connect(m_serialPort, &QSerialPort::readyRead, [&]() {
        auto rcvData = m_serialPort->readAll();
        ret = QString::fromLatin1(rcvData);
        emit sig_finishReadSerial();
    });

    loop.exec();
    QObject::disconnect(async);
    return ret;
}
```

 


posted @ 2017-04-04 13:11  朱小勇  阅读(7332)  评论(0)    收藏  举报