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; } ```
长风破浪会有时,直挂云帆济沧海!
可通过下方链接找到博主
https://www.cnblogs.com/judes/p/10875138.html