Qt串口回路信號(hào)讀取多線程14串口測(cè)試方案
QSerialPort串口
一、思路
串口測(cè)試分為三種:
- 回路測(cè)試
- 對(duì)傳
- 485模式,可以傳輸更遠(yuǎn)的距離
二、環(huán)境
- Qt 6.4.3
- Qt serial port模塊
- Qt Creator 11.0.1
三、添加QSerialPort
- 打開(kāi)Qt mataintenanceTool
- 登錄
- 添加/移動(dòng)組件,點(diǎn)擊下一步
- 主要是選擇Qt Serial Bus, Qt Serial Port
- 點(diǎn)擊下一步
- 點(diǎn)擊更新即可
四、語(yǔ)句介紹
1.數(shù)據(jù)控制流
數(shù)據(jù)控制流 USART_HardwareFlowControl ,控制流,這里的流指數(shù)據(jù)流,在數(shù)據(jù)傳輸中,流控制室管理兩個(gè)節(jié)點(diǎn)之間數(shù)據(jù)傳輸速率過(guò)程,以防止出現(xiàn)接收端的數(shù)據(jù)緩存區(qū)已滿,而發(fā)送端依然繼續(xù)發(fā)送數(shù)據(jù),所以導(dǎo)致數(shù)據(jù)丟失。
(1) 工作原理
當(dāng)接受端的數(shù)據(jù)緩沖區(qū)已滿,無(wú)法處理數(shù)據(jù)來(lái)時(shí),就發(fā)出不再接受的信號(hào),發(fā)送端則停止發(fā)送,直到發(fā)送端收到可以繼續(xù)發(fā)送的信號(hào)再發(fā)送數(shù)據(jù),常見(jiàn)的硬件控制流和軟件控制流
(2) 硬件控制流
硬件控制流
RTS和CTS原本是用來(lái)詢問(wèn)和回答是否可以傳輸數(shù)據(jù)。在上面的連接上,就是告訴對(duì)方自己子否可以進(jìn)行通訊,此時(shí)RTS和DTR都可以用來(lái)對(duì)數(shù)據(jù)流進(jìn)行控制。
A端DTR(數(shù)據(jù)設(shè)備就緒)發(fā)出信號(hào),當(dāng)B端準(zhǔn)備好后,B端的DTR(數(shù)據(jù)設(shè)備就緒)向A端的DSR(通訊設(shè)備就緒發(fā)送信號(hào)),然后就可以通過(guò)RTS(請(qǐng)求發(fā)送)和DTR(允許發(fā)送)來(lái)控制通信。
硬件控制流并不是單純依賴硬件,它仍然需要軟件去處理識(shí)別,硬件控制流所做的只是給出信號(hào)電平。
(3) 軟件控制流
軟件流控制(Software flow control)是在計(jì)算機(jī)數(shù)據(jù)鏈路中的一種控制方法,特別適合于RS-232串口通信;它是采用特殊字符來(lái)船速帶內(nèi)信令,特殊編碼字符稱作XOFF與XON(分別表示transmit off與transmit on)。因此也被稱作XON/XOFF流控制
使用ASCII字符集,XOFF一般為字節(jié)值19(十進(jìn)制),XON為字節(jié)值17
(4) 工作方式
注意:是接收方把XON/XOFF信號(hào)發(fā)給發(fā)送方來(lái)控制發(fā)送方何時(shí)發(fā)送數(shù)據(jù),這些信號(hào)是與發(fā)送數(shù)據(jù)的傳輸方向相反的。
接收方利用XON信號(hào)告訴發(fā)送方,我已經(jīng)準(zhǔn)備好接受更多的數(shù)據(jù)了,利用XOFF信號(hào)告訴發(fā)送方停止發(fā)送數(shù)據(jù),直到接收方發(fā)送XON信號(hào)告訴發(fā)送方我再次準(zhǔn)備好了。
(5) 設(shè)置控制流模式
setFlowControl 函數(shù):
// setFlowControl對(duì)端口控制進(jìn)行相關(guān)設(shè)置 無(wú)流量控制
serial->setFlowControl(QSerialPort::NoFlowControl);
- NoFlowControl:沒(méi)有控制
- hardware flow control :硬件流控制 (RTS/CTS,DTR /DSR等)
- Software flow control :軟件流控制 (XON/XOFF)
設(shè)置控制流
2.設(shè)置端口
設(shè)置端口的名稱,此名字可以使用短名稱或者長(zhǎng)系統(tǒng)地址。
void QSerialPort::setPortName(const QString &name)
3.波特率
輸出傳輸?shù)乃俾?,每秒傳輸?shù)谋忍財(cái)?shù)。
enum QSerialPort::BaudRate
/// 可以選擇的內(nèi)容為
Constant | Value | Description |
QSerialPort::Baud1200 | 1200 | 1200 baud. |
QSerialPort::Baud2400 | 2400 | 2400 baud. |
QSerialPort::Baud4800 | 4800 | 4800 baud. |
QSerialPort::Baud9600 | 9600 | 9600 baud. |
QSerialPort::Baud19200 | 19200 | 19200 baud. |
QSerialPort::Baud38400 | 38400 | 38400 baud. |
QSerialPort::Baud57600 | 57600 | 57600 baud. |
QSerialPort::Baud115200 | 115200 | 115200 baud. |
4.數(shù)據(jù)位
設(shè)置數(shù)據(jù)位并保存到幀中,如果設(shè)置成功,則返回true,否則返回false,并設(shè)置一個(gè)錯(cuò)誤代碼,可以通過(guò)訪問(wèn)QSerialPort::error屬性的值來(lái)獲取該代碼。
如果在打開(kāi)端口之前設(shè)置了該設(shè)置,則實(shí)際的串行端口設(shè)置將在QSerialPort::open()方法中自動(dòng)完成,然后端口打開(kāi)成功。
bool setDataBits(DataBits dataBits);
DataBits dataBits() const;
數(shù)據(jù)位
5.奇偶校驗(yàn)位
奇偶校驗(yàn)位
bool setParity(Parity parity);
Parity parity() const;
6.設(shè)置停止位
停止位
bool setStopBits(StopBits stopBits);
StopBits stopBits() const;
7.發(fā)送方式
Hex 16進(jìn)制,本質(zhì)上就是將字節(jié)數(shù)數(shù)組轉(zhuǎn)化為16進(jìn)制,然后用字符串的形式發(fā)送出去。
五、對(duì)于ui參數(shù)隨數(shù)字變化如何設(shè)置
int p = 1;
foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
{
PortStringList += info.portName();
ui->port->addItem(info.portName());
// 構(gòu)造對(duì)象名
QString objectName = QString("comlist%1").arg(p);
// 查找對(duì)象
QLineEdit *comlist = this->findChild<QLineEdit *>(objectName);
if(comlist) {
comlist->setText(info.portName());
}
p++;
}
六、字符串截取
QString snap = QString("COM");
int com_num = com.remove(snap).toInt();
七、源代碼
linux與windows端通用多線程串口,可同時(shí)檢測(cè)14個(gè)串口。
1.Com_Test.pro
QT += core gui
QT += serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# 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 += \
comthread.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
comthread.h \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
2.comthread.h
#ifndef COMTHREAD_H
#define COMTHREAD_H
#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QThread>
class ComThread :public QObject
{
Q_OBJECT
public:
explicit ComThread(QObject *parent = nullptr);
explicit ComThread(QString portname,qint32 rate,qint32 date,qint32 check_num,qint32 stop_num);
explicit ComThread(qint32 rate,qint32 date,qint32 check_num,qint32 stop_num);
explicit ComThread(QString portname);
// 拷貝構(gòu)造函數(shù)
explicit ComThread(const ComThread &other);
ComThread& operator = (const ComThread &other)
{
qDebug()<<"進(jìn)入拷貝";
if(this != &other)
{
qDebug()<<"進(jìn)入拷貝賦值";
this->m_com = other.m_com;
this->mSerialPort = other.mSerialPort;
this->m_check_num = other.m_check_num;
this->m_date = other.m_date;
this->m_rate = other.m_rate;
this->m_stop_num = other.m_stop_num;
qDebug()<<"賦值結(jié)束";
}
qDebug()<<"返回值";
return *this;
}
~ ComThread();
public slots:
// 接受傳入的串口數(shù)據(jù)
void slot_recv_com(QString portname,qint32 rate,qint32 date,qint32 check_num,qint32 stop_num);
void slot_recv_com_s(qint32 rate,qint32 date,qint32 check_num,qint32 stop_num);
void slot_recv_com_name(QString portname);
// 對(duì)應(yīng)主線程的信號(hào),需要的槽函數(shù)
// 1,打開(kāi)串口槽函數(shù)
// 2,關(guān)閉串口槽函數(shù)
void slot_openPort();
void slot_closePort();
void slot_handlMessage();
void serial_signal();
private:
QSerialPort* mSerialPort;
QString m_com;
qint32 m_rate;
qint32 m_date;
qint32 m_check_num;
qint32 m_stop_num;
QByteArray Receivetext;
signals:
// 發(fā)送信號(hào)
// 發(fā)送字節(jié)
void already_send_byte(QString com ,qint32 num);
// 發(fā)送接受字節(jié)
void already_receive_byte(QString com ,qint32 num);
// 發(fā)送是否成功
void result(QString com ,qint32 num); // 0代表失敗 1,代表成功
// 發(fā)送接受字符串
void already_receive_string(QString com ,QString string);
void send_com_signal(QString com,bool DTRstate,bool DCDstate,bool DSRstate,bool RINGRstate,bool RTSstate,bool CTSstate,bool STDstate,bool SRDstate);
};
#endif // COMTHREAD_H
3.comthread.cpp
#include "comthread.h"
ComThread::ComThread(QObject *parent)
: QObject{parent}
{
// mSerialPort = nullptr;
}
ComThread::ComThread(QString portname)
{
m_com = portname;
}
ComThread::ComThread(const ComThread &other)
{
// qDebug()<<"進(jìn)入賦值拷貝";
this->m_com = other.m_com;
this->mSerialPort = other.mSerialPort;
this->m_check_num = other.m_check_num;
this->m_date = other.m_date;
this->m_rate = other.m_rate;
this->m_stop_num = other.m_stop_num;
}
ComThread::ComThread(QString portname, qint32 rate,qint32 date,qint32 check_num,qint32 stop_num)
{
m_com = portname;
m_rate = rate;
m_date = date;
m_check_num = check_num;
m_check_num = stop_num;
}
ComThread::ComThread(qint32 rate, qint32 date, qint32 check_num, qint32 stop_num)
{
m_rate = rate;
m_date = date;
m_check_num = check_num;
m_check_num = stop_num;
}
ComThread::~ComThread()
{
if(mSerialPort->isOpen())
{
mSerialPort->close();
}
delete mSerialPort;
}
void ComThread::slot_recv_com(QString portname, qint32 rate, qint32 date, qint32 check_num, qint32 stop_num)
{
m_com = portname;
m_rate = rate;
m_date = date;
m_check_num = check_num;
m_stop_num = stop_num;
}
void ComThread::slot_recv_com_s(qint32 rate, qint32 date, qint32 check_num, qint32 stop_num)
{
m_rate = rate;
m_date = date;
m_check_num = check_num;
m_stop_num = stop_num;
}
void ComThread::slot_recv_com_name(QString portname)
{
m_com = portname;
}
void ComThread::slot_openPort()
{
mSerialPort = new QSerialPort();
// qDebug()<<" "<< m_com<<" "<<m_rate<<" "<<m_date<<" "<<m_check_num<<" "<<m_stop_num;
// 設(shè)置串口對(duì)應(yīng)的名稱和波特率
mSerialPort->setPortName(m_com);
mSerialPort->setBaudRate(m_rate);
switch(m_date)
{
//設(shè)置對(duì)應(yīng)的數(shù)據(jù)位
case5:mSerialPort->setDataBits(QSerialPort::Data5);break;
case6:mSerialPort->setDataBits(QSerialPort::Data6);break;
case7:mSerialPort->setDataBits(QSerialPort::Data7);break;
case8:mSerialPort->setDataBits(QSerialPort::Data8);break;
// 若剛開(kāi)始設(shè)置為空,端口打開(kāi)之后再次進(jìn)行相關(guān)的設(shè)置
// 若沒(méi)有選擇就不設(shè)置,端口打開(kāi)之后仍可以設(shè)置
//default:serial->setDataBits(QSerialPort::UnknownDataBits);
}
switch(m_check_num)
{
case0:mSerialPort->setParity(QSerialPort::NoParity);break;
case1:mSerialPort->setParity(QSerialPort::EvenParity);break;
case2:mSerialPort->setParity(QSerialPort::OddParity);break;
case3:mSerialPort->setParity(QSerialPort::SpaceParity);break;
case4:mSerialPort->setParity(QSerialPort::MarkParity);break;
//default:serial->setParity(QSerialPort::UnknownParity);
}
switch(m_stop_num)
{
case0:mSerialPort->setStopBits(QSerialPort::OneStop);break;
case1:mSerialPort->setStopBits(QSerialPort::OneAndHalfStop);break;
case2:mSerialPort->setStopBits(QSerialPort::TwoStop);break;
//default:serial->setStopBits(QSerialPort::UnknownStopBits);
}
// 關(guān)聯(lián)讀取信號(hào)與槽函數(shù),處理信息
mSerialPort->setFlowControl(QSerialPort::NoFlowControl);
connect(mSerialPort,&QSerialPort::readyRead,this,&ComThread::slot_handlMessage);
qDebug()<<"ComThread slot_openport ThreadID"<< QThread::currentThreadId();
if(mSerialPort->open(QIODevice::ReadWrite))
{
this->serial_signal();
// 發(fā)送數(shù)據(jù)
for(int i = 0;i<5;i++)
{
QString realbom = QString("RealReal");
QByteArray send = realbom.toUtf8();
// qDebug()<<send<<"Byte大小:"<<send.length();
mSerialPort->write(send);
emit already_send_byte(m_com,send.length());
// QThread::msleep(1000);
mSerialPort->waitForReadyRead(10); // 接受數(shù)據(jù)
}
// qDebug()<<"發(fā)送完畢";
// mSerialPort->waitForReadyRead(100); // 接受數(shù)據(jù)
this->slot_closePort();
}
else
{
// qDebug()<<"return false";
// 關(guān)閉信號(hào)
emit result(m_com,0);
};
if(Receivetext.size() == 0)
{
//完全沒(méi)有接收到數(shù)據(jù)
emit result(m_com,0);
}
}
void ComThread::slot_closePort()
{
if(mSerialPort->isOpen())
{
mSerialPort->close();
}
}
void ComThread::slot_handlMessage()
{
qDebug()<<"調(diào)用了此信號(hào)";
// mSerialPort->waitForBytesWritten(100);
Receivetext = mSerialPort->readAll();
// qDebug()<<"接收:"<<QString::fromUtf8(Receivetext)<<"Byte大小:"<<Receivetext.length();
emit already_receive_byte(m_com,Receivetext.length());
emit already_receive_string(m_com,QString::fromUtf8(Receivetext));
if(Receivetext == QString("RealReal") && Receivetext.length() == 7)
{
emit result(m_com,1);
}
else
{
emit result(m_com,0);
}
}
void ComThread::serial_signal()
{
// 獲取相關(guān)高低電壓值No
// bool NOstate = serial->pinoutSignals()& QSerialPort::NoSignal; // 沒(méi)有信號(hào)
// 數(shù)據(jù)終端準(zhǔn)備好
bool DTRstate = mSerialPort->pinoutSignals()& QSerialPort::DataTerminalReadySignal;
// 載波信號(hào)
bool DCDstate = mSerialPort->pinoutSignals()& QSerialPort::DataCarrierDetectSignal;
// 數(shù)據(jù)準(zhǔn)備好
bool DSRstate = mSerialPort->pinoutSignals()& QSerialPort::DataSetReadySignal;
//
bool RINGRstate = mSerialPort->pinoutSignals()& QSerialPort::RingIndicatorSignal;
// 請(qǐng)求發(fā)送
bool RTSstate = mSerialPort->pinoutSignals()& QSerialPort::RequestToSendSignal;
// 清除發(fā)送
bool CTSstate = mSerialPort->pinoutSignals()& QSerialPort::ClearToSendSignal;
// 發(fā)送數(shù)據(jù)
bool STDstate = mSerialPort->pinoutSignals()& QSerialPort::SecondaryTransmittedDataSignal;
// 接受數(shù)據(jù)
bool SRDstate = mSerialPort->pinoutSignals()& QSerialPort::SecondaryReceivedDataSignal;
emit send_com_signal(m_com,DTRstate,DCDstate,DSRstate,RINGRstate,RTSstate,CTSstate,STDstate,SRDstate);
/*
if(DTRstate)
{
// ui->DTR->setStyleSheet("background-color:red");
qDebug()<<"DTRstate";
}
if(DCDstate)
{
// ui->DCD->setStyleSheet("background-color:red");
qDebug()<<"DCDstate";
}
if(DSRstate)
{
// ui->DSR->setStyleSheet("background-color:red");
qDebug()<<"DSRstate";
}
if(RINGRstate)
{
// ui->PNG->setStyleSheet("background-color:red");
qDebug()<<"RINGRstate";
}
if(RTSstate)
{
// ui->RTS->setStyleSheet("background-color:red");
qDebug()<<"RTSstate";
}
if(CTSstate)
{
// ui->CTS->setStyleSheet("background-color:red");
qDebug()<<"CTSstate";
}
if(STDstate)
{
// ui->STD->setStyleSheet("background-color:red");
qDebug()<<"STDstate";
}
if(SRDstate)
{
// ui->SRD->setStyleSheet("background-color:red");
qDebug()<<"SRDstate";
}
*/
}
4.mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "comthread.h"
#include <QThread>
//#include <QThreadPool>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow :public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void sig_recv_com(QString portname, qint32 rate, qint32 date, qint32 check_num, qint32 stop_num);
void sig_recv_com_s(qint32 rate, qint32 date, qint32 check_num, qint32 stop_num);
void sig_recv_com_name(QString portname);
void sig_openPort();
void sig_closePort();
public slots:
// 接受子線程傳回的數(shù)據(jù)
void slots_already_send_byte(QString com ,qint32 num);
// 接受字節(jié)
void slots_already_receive_byte(QString com ,qint32 num);
// 是否成功
void slots_result(QString com ,qint32 num); // 0代表失敗 1,代表成功
// 接受字符串
void slots_already_receive_string(QString com ,QString string);
// 接受引腳信號(hào)
void send_com_signal(QString com,bool DTRstate,bool DCDstate,bool DSRstate,bool RINGRstate,bool RTSstate,bool CTSstate,bool STDstate,bool SRDstate);
private slots:
void on_serial_test_clicked();
protected:
private:
Ui::MainWindow *ui;
QStringList PortStringList; // 串口列表
// QThreadPool *pool = QThreadPool::globalInstance();
ComThread *comthread;
// std::vector<ComThread> comthread;
QThread *mthread;
QString snap;
};
#endif // MAINWINDOW_H
5.mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//設(shè)計(jì)循環(huán),將數(shù)據(jù)放入list列表當(dāng)中
int p =1;
foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
{
PortStringList += info.portName();
ui->port->addItem(info.portName());
// 構(gòu)造對(duì)象名
QString objectName = QString("comlist%1").arg(p);
// 查找對(duì)象
QLineEdit *comlist = this->findChild<QLineEdit *>(objectName);
if(comlist) {
comlist->setText(info.portName());
}
p++;
}
//設(shè)置UI頁(yè)面的默認(rèn)Index
ui->bo_num->setCurrentIndex(5);
ui->data_num->setCurrentIndex(3);
ui->check_num->setCurrentIndex(2);
ui->stop_num->setCurrentIndex(0);
}
MainWindow::~MainWindow()
{
delete ui;
if(mthread->isRunning())
{
mthread->quit();
mthread->wait();
delete[] mthread;
// delete[] comthread;
}
}
void MainWindow::slots_already_send_byte(QString com, int num)
{
int com_num = com.remove(snap).toInt();
QString objectname = QString("send_byte_") + QString::number(com_num);
QLabel *label = this->findChild<QLabel *>(objectname);
if(label)
{
label->setText(QString::number(num));
}
qDebug()<<com<<"已發(fā)送"<<num;
}
void MainWindow::slots_already_receive_byte(QString com, int num)
{
int com_num = com.remove(snap).toInt();
QString objectname = QString("recv_byte_") + QString::number(com_num);
QLabel *label = this->findChild<QLabel *>(objectname);
if(label)
{
label->setText(QString::number(num));
}
qDebug()<<com<<"已接收"<<num;
}
void MainWindow::slots_result(QString com, int num)
{
int com_num = com.remove(snap).toInt();
QString objectname = QString("list_result_") + QString::number(com_num);
QPushButton *button = this->findChild<QPushButton *>(objectname);
if(button)
{
if(1 == num)
{
button->setText("通過(guò)");
button->setStyleSheet("background-color:rgb(27,167,132)");
}
else
{
button->setText("失敗");
button->setStyleSheet("background-color:rgb(238, 72, 99)");
}
}
qDebug()<<com<<"測(cè)試結(jié)果(0代表失敗 1,代表成功)"<<num;
}
void MainWindow::slots_already_receive_string(QString com, QString string)
{
int com_num = com.remove(snap).toInt();
QString objectname = QString("recv_date_") + QString::number(com_num);
QLineEdit *Edit = this->findChild<QLineEdit *>(objectname);
if(Edit)
{
Edit->setText(string);
}
qDebug()<<com<<"已接收字符串"<<string;
}
void MainWindow::send_com_signal(QString com, bool DTR, bool DCD, bool DSR, bool RNG, bool RTS, bool CTS, bool STD, bool SRD)
{
int com_num = com.remove(snap).toInt();
{
if(DTR)
{
QString objectname = QString("DTR_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
if(DCD)
{
QString objectname = QString("DCD_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
if(DSR)
{
QString objectname = QString("DSR_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
if(RNG)
{
QString objectname = QString("RNG_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
if(RTS)
{
QString objectname = QString("RTS_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
if(CTS)
{
QString objectname = QString("CTS_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
if(STD)
{
QString objectname = QString("STD_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
if(SRD)
{
QString objectname = QString("SRD_") + QString::number(com_num);
QToolButton *ToolButton = this->findChild<QToolButton *>(objectname);
if(ToolButton)
{
ToolButton->setStyleSheet("background-color:rgb(240, 124, 130)");
}
}
}
qDebug()<<"com"<<"DTRstate"<<"DCDstate"<<"DSRstate"<<"RINGRstate"<<"RTSstate"<<"CTSstate"<<"STDstate"<<"SRDstate";
qDebug()<<com<<DTR<<DCD<<DSR<<RNG<<RTS<<CTS<<STD<<SRD;
}
// 點(diǎn)擊進(jìn)入串口回路測(cè)試
void MainWindow::on_serial_test_clicked()
{
// 判斷當(dāng)前系統(tǒng)
#ifdef Q_OS_WIN
snap = QString("COM");
#elif defined(Q_OS_LINUX)
snap = QString("ttyS");
#endif
int qserial_size = PortStringList.size();
bool open_test[qserial_size];
for (int i = 0; i < qserial_size; ++i) {
open_test[i] = true;
}
// 獲取串口等信息
QString Port = ui->port->currentText();
qint32 rate = ui->bo_num->currentText().toInt();
qint32 date = ui->data_num->currentText().toInt();
qint32 check_num = ui->check_num->currentIndex();
qint32 stop_num = ui->stop_num->currentIndex();
// qDebug()<<"檢查位:"<<check_num<<"停止位:"<<stop_num;
// TODO多com口同時(shí)測(cè)試 14個(gè)線程
mthread = new QThread[qserial_size];
/*
// comthread = new ComThread(Port,rate,date,check_num,stop_num);
// comthread = new ComThread[14](Port,rate,date,check_num,stop_num);
// ComThread * comthread = new ComThread[PortStringList.size()];
// comthread = new ComThread[qserial_size];
// 為每個(gè)元素分配對(duì)應(yīng)的端口,并初始化ComThread對(duì)象數(shù)組
// for (int i = 0; i < qserial_size; ++i) {
// comthread[i] = ComThread(PortStringList.at(i));
// }
*/
/*
for(int m = 0;m < qserial_size; m++)
{
// comthread[m] = ComThread(PortStringList.at(m));
// comthread.emplace_back(ComThread(PortStringList.at(m)));
}
{
ComThread(PortStringList.at(0)),
ComThread(PortStringList.at(1)),
ComThread(PortStringList.at(2)),
ComThread(PortStringList.at(3)),
ComThread(PortStringList.at(4)),
ComThread(PortStringList.at(5)),
ComThread(PortStringList.at(6)),
ComThread(PortStringList.at(7)),
ComThread(PortStringList.at(8)),
ComThread(PortStringList.at(9)),
ComThread(PortStringList.at(10)),
ComThread(PortStringList.at(11)),
ComThread(PortStringList.at(12)),
ComThread(PortStringList.at(13)),
};
*/
int i = 0;
foreach(QString com_e,PortStringList)
{
ComThread *comthread = new ComThread(com_e);
// qDebug()<<com_e;
// 移入線程
// comthread[i].moveToThread(&mthread[i]);
comthread->moveToThread(&mthread[i]);
mthread[i].start();
//關(guān)聯(lián)信號(hào)
if(open_test[i])
{
// connect(this,&MainWindow::sig_openPort,&comthread[i],&ComThread::slot_openPort);
// connect(this,&MainWindow::sig_recv_com_s,&comthread[i],&ComThread::slot_recv_com_s);
connect(this,&MainWindow::sig_openPort,comthread,&ComThread::slot_openPort);
connect(this,&MainWindow::sig_recv_com_s,comthread,&ComThread::slot_recv_com_s);
// 關(guān)聯(lián)返回信號(hào)
connect(comthread,&ComThread::already_receive_byte,this,&MainWindow::slots_already_receive_byte);
connect(comthread,&ComThread::already_receive_string,this,&MainWindow::slots_already_receive_string);
connect(comthread,&ComThread::already_send_byte,this,&MainWindow::slots_already_send_byte);
connect(comthread,&ComThread::result,this,&MainWindow::slots_result);
connect(comthread,&ComThread::send_com_signal,this,&MainWindow::send_com_signal);
open_test[i] = false;
}
qDebug()<<"main ThreaiD:"<<QThread::currentThreadId();
emit sig_recv_com_s(rate,date,check_num,stop_num);
emit sig_openPort();
// pool->start(comthread);
{
// 取消單個(gè)信號(hào)對(duì)所有串口的信號(hào)連接
// disconnect(this,&MainWindow::sig_openPort,&comthread[i],&ComThread::slot_openPort);
// disconnect(this,&MainWindow::sig_recv_com_s,&comthread[i],&ComThread::slot_recv_com_s);
disconnect(this,&MainWindow::sig_openPort,comthread,&ComThread::slot_openPort);
disconnect(this,&MainWindow::sig_recv_com_s,comthread,&ComThread::slot_recv_com_s);
}
i++;
// pool->waitForDone();
//
qDebug()<<"執(zhí)行結(jié)束";
// QThread::sleep(1);
// mthread->quit();
// mthread[0].isFinished();
}
// 循環(huán)結(jié)束線程
for(int j = 0;j<PortStringList.size();j++)
{
if(mthread[j].isFinished())
{
// qDebug()<<"quit"<<j;
mthread[j].quit();
mthread[j].wait();
}
else
{
// qDebug()<<"wait"<<j;
mthread[j].quit();
mthread[j].wait();
}
}
// delete [] mthread;
}
6.main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
八、問(wèn)題解決
1.多線程中出現(xiàn)QObject: Cannot create children for a parent that is in a different thread
這個(gè)錯(cuò)誤提示的實(shí)際意思是,不能在子線程中生成跨線程調(diào)用的成員。如果一個(gè)成員在父線程中被直接調(diào)用了,那么這個(gè)成員必須處在父線程中,強(qiáng)行在子線程中生成就會(huì)出現(xiàn)這個(gè)錯(cuò)誤提示。
將在多線程中構(gòu)造函數(shù)中new出來(lái)的變量,放到run中執(zhí)行,因?yàn)闃?gòu)造函數(shù)是在主線程完成初始化的,線程所屬于不同的線程,就會(huì)出現(xiàn)此類錯(cuò)誤。
解決此問(wèn)題的關(guān)鍵將線程放到一個(gè)地方,例如子線程中的對(duì)串口的new定義。
2.munmap_chunk(): invalid pointer解決方案線程池釋放,程序崩潰
程序分析:將程序線程池取消自動(dòng)釋放,結(jié)果程序確實(shí)沒(méi)有發(fā)生崩潰,可以繼續(xù)運(yùn)行,所以分析斷定,程序崩潰為線程池析構(gòu)時(shí)的問(wèn)題。
展示關(guān)閉線程自動(dòng)銷毀功能,同時(shí)程序中多次使用。
解決方案:檢查程序結(jié)束,或者異常結(jié)束資源銷毀問(wèn)題。
3.循環(huán)發(fā)送信息,并沒(méi)有收到數(shù)據(jù),而是最后一起收到數(shù)據(jù)
在發(fā)送數(shù)據(jù)之后,加入waitForReadyRead(10);函數(shù),就會(huì)接受數(shù)據(jù),此函數(shù)功能為等待接受,與其說(shuō)等待,其實(shí)立馬就接受了數(shù)據(jù)。否則在測(cè)試當(dāng)中出現(xiàn)了五次循環(huán)結(jié)束,一同接受數(shù)據(jù)的情況。
for(int i = 0;i<5;i++)
{
QString realbom = "realbom";
QByteArray send = realbom.toUtf8();
qDebug()<<send;
mSerialPort->write(send);
// QThread::sleep(1);
mSerialPort->waitForReadyRead(10); // 接受數(shù)據(jù)
}
4.接受數(shù)據(jù)和發(fā)送數(shù)據(jù)格式不同,接受數(shù)據(jù)亂碼
- 查詢是否是串口參數(shù)配置問(wèn)題。我的確實(shí)是此問(wèn)題,當(dāng)時(shí)確實(shí)是玩完沒(méi)有想到,設(shè)置默認(rèn)值之后,就可以
- 設(shè)置正確的編碼轉(zhuǎn)換關(guān)系
QByteArray send = realbom.toUtf8();
qDebug()<<send<<"Byte大小:"<<send.length();
mSerialPort->write(send);
QByteArray Receivetext = mSerialPort->readAll();
qDebug()<<"接收:"<<QString::fromUtf8(Receivetext)<<"Byte大小:"<<Receivetext.length();