概 述
Qt中提供了QSerialPort
類來實(shí)現(xiàn)串口相關(guān)的操作,本文介紹Qt中如何使用QSerialPort
類來實(shí)現(xiàn)串口通信。
.pro
文件中添加
QT += serialport
頭文件
#include <QSerialPort>
#include <QSerialPortInfo> //用于獲取串口數(shù)據(jù)
實(shí) 現(xiàn)
一到忽、獲取串口信息
使用QSerialPortInfo::availablePorts()
或辖,獲取系統(tǒng)上可用的串口列表。即QSerialPortInfo對(duì)象列表:QList<QSerialPortInfo>
忌堂,列表中的每個(gè)QSerialPortInfo對(duì)象表示一個(gè)串行端口,可以查詢端口名稱酗洒、系統(tǒng)位置士修、描述等信息。
//遍歷返回的QSerialPortInfo對(duì)象列表
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
//將串口名稱添加到界面下拉框中
ui->serialName->addItem(info.portName());
}
二樱衷、設(shè)置串口信息
打開串口前棋嘲,先對(duì)串口的相關(guān)配置進(jìn)行設(shè)置,例如連接的串口名稱矩桂、波特率沸移、數(shù)據(jù)位等等。
m_serialPort->setPortName(ui->serialName->currentText()); //設(shè)置串口名稱侄榴,使用界面下拉框中的串口
m_serialPort->setBaudRate(QSerialPort::Baud115200); //設(shè)置波特率
m_serialPort->setDataBits(QSerialPort::Data8); //設(shè)置數(shù)據(jù)位
m_serialPort->setStopBits(QSerialPort::OneStop); //設(shè)置停止位
m_serialPort->setParity(QSerialPort::NoParity); //設(shè)置有無校驗(yàn)位
m_serialPort->setFlowControl(QSerialPort::NoFlowControl); //設(shè)置流控制
三雹锣、打開串口
void MainWindow::on_serialOpenBtn_clicked()
{
if (!m_serialPort->isOpen()) {
if (m_serialPort->open(QIODevice::ReadWrite)) { //以讀寫方式打開串口
m_serialPort->clear(); //每次打開串口,先清空一次緩沖區(qū)數(shù)據(jù)
connect(m_serialPort, SIGNAL(readyRead()), SLOT(onReadyRead())); //連接數(shù)據(jù)讀取信號(hào)槽
qDebug() << "打開成功";
} else {
qDebug() << "打開失敗";
}
} else {
m_serialPort->clear();
m_serialPort->close();
qDebug() << "關(guān)閉";
}
}
四癞蚕、數(shù)據(jù)交互
//發(fā)送數(shù)據(jù)
void MainWindow::on_sendData_Btn_clicked()
{
QByteArray data;
//根據(jù)于下位機(jī)定義的協(xié)議笆制,自定義數(shù)據(jù)內(nèi)容
//...
qint64 writeLen = m_serialPort->write(data);
if (writeLen == -1) {
qDebug() << "數(shù)據(jù)發(fā)送失敗";
} else {
qDebug() << "數(shù)據(jù)發(fā)送成功";
}
}
//讀取數(shù)據(jù)
//在打開串口時(shí),連接的槽函數(shù)
void MainWindow::onReadyRead()
{
//簡(jiǎn)單的讀取所有數(shù)據(jù)
QByteArray data = m_serialPort->readAll();
qDebug() << "Data:" << data;
//根據(jù)自定義協(xié)議涣达,處理數(shù)據(jù)
//...
}
注:對(duì)于復(fù)雜的通信協(xié)議在辆,為了避免丟包等一系列問題造成的數(shù)據(jù)丟失,簡(jiǎn)單的readAll()
并不能滿足要求度苔,Qt提供了以下的函數(shù):
//返回等待讀取的傳入字節(jié)數(shù)匆篓。
bytesAvailable()
//從設(shè)備讀取maxSize字節(jié)數(shù)據(jù)(此方法的讀取,不會(huì)將數(shù)據(jù)從緩沖區(qū)取走)
peek(char *data, qint64 maxSize)
//在設(shè)備上啟動(dòng)新的讀取事務(wù)
startTransaction()
//完成讀取事務(wù)
commitTransaction()
//回滾讀取事務(wù)
rollbackTransaction()
簡(jiǎn)單的示例:
void MainWindow::onReadyRead()
{
MSG_HEAD msgHead; //自定義的協(xié)議消息頭
qint64 bytes;
uint32_t flag; //自定義協(xié)議中的標(biāo)志位
while (true) {
bytes = m_serialPort->bytesAvailable();
if (bytes >= qint64(sizeof flag)) { //flag為自定義協(xié)議中的標(biāo)志位寇窑,用于判斷是否為有效的協(xié)議數(shù)據(jù)
//peek flag長(zhǎng)度的數(shù)據(jù)鸦概,但不從緩沖區(qū)中取出
m_serialPort->peek(reinterpret_cast<char *>(&flag), sizeof flag);
if (flag == FLAG) { //判斷標(biāo)志位,
m_serialPort->startTransaction(); //開啟事務(wù)
m_serialPort->read(reinterpret_cast<char *>(&msgHead), sizeof(MSG_HEAD)); //讀取協(xié)議消息頭
bytes -= sizeof(MSG_HEAD); //減去協(xié)議消息頭長(zhǎng)度
if (bytes >= msgHead.msgLen) { //判斷剩余數(shù)據(jù)長(zhǎng)度是否大于協(xié)議消息體長(zhǎng)度
handleAddrData(m_serialPort->read(ackHead.msgLen)); //讀取消息體長(zhǎng)度的數(shù)據(jù)
//數(shù)據(jù)處理
//...
m_serialPort->commitTransaction(); //提交讀取事務(wù)
continue;
}
m_serialPort->rollbackTransaction(); //數(shù)據(jù)長(zhǎng)度不足,回滾讀取事務(wù)
}
}
break;
}
}
五窗市、析構(gòu)
清理緩沖區(qū)并關(guān)閉串口
if (m_serialPort->isOpen()) {
m_serialPort->clear();
m_serialPort->close();
}
delete m_serialPort;