很多小夥伴們對串口編程剛上手時,不知道如何下手,本例子帶大家看看一個簡單的串口通訊的例子,例子是網上的demo,這裏簡單的介紹下:
這是我們常見的界面窗口,下面我們來解析下代碼部分:
串口步驟:
* 1.設置串口參數
* 2.打開串口
* 3.讀/寫串口
* 4.關閉串口
#ifndef SERIALPORT_H
#define SERIALPORT_H
#include <QMainWindow>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QLabel>
#include <QPushButton>
#include <QCloseEvent>
namespace Ui {
class SerialPort;
}
class SerialPort : public QMainWindow
{
Q_OBJECT
public:
explicit SerialPort(QWidget *parent = 0);
~SerialPort();
/* 初始狀態欄 */
void InitStatusBar(); // 初始化狀態欄
void SetSerState(); // 設置狀態欄串口狀態
void SetRecvNum(); // 設置接收字節數
void SetSendNum(); // 設置發送字節數
/* 初始化CombBox控件 */
void InitCommCmb(); // 初始化CombBox控件
void SetPortNumCmb(); // 設置串口號
QStringList GetEnableCommPortQt(); // 獲取計算機可用串口 Qt方式
QStringList GetEnableCommPortWin(); // 獲取計算機可用串口 Windows API方式
QString GetComm(int nIndex, bool bValue = true);
void SetBaudCmb(); // 設置波特率
void SetDPaityCmb(); // 設置校驗位
void SetDataBCmb(); // 設置數據位
void SetStopBCmb(); // 設置停止位
void SetStreamCmb(); // 設置流控制
bool SetSerialPortParam(QSerialPort *serial); // 設置串口參數,失敗返回false,成功返回true
/* 父類函數重寫 */
void closeEvent(QCloseEvent *event);
private slots:
void on_baudRCmb_currentIndexChanged(int index); // 自定義波特率
void on_OnOffBtn_clicked(); // 打開/斷開串口
void on_ReflushSerPortBtn_clicked(); // 刷新串口,重新掃描計算機可用串口
void slot_RecvPortData(); // 接收串口數據
void on_SendBtn_clicked(); // 發送數據
void on_ClearRecvBtn_clicked(); // 清空接收區
void slot_ResetNumBtn_clicked(); // 復位計數
private:
Ui::SerialPort *ui;
/* 狀態欄控件 */
QLabel *m_SerStateLbl; // 串口狀態
QLabel *m_RecvNumLbl; // 接收字節數
QLabel *m_SendNumLbl; // 發送字節數
QPushButton *m_ResetNumBtn; // 復位計數按鈕
/* 發送、接收字節數 */
uint m_nRecvNum; // 接收字節數
uint m_nSendNum; // 發送字節數
bool m_bOpen; // 標識串口狀態
QSerialPort *m_serial; // 串口通信類對象
qint64 m_nReadBuffSize; // 串口緩衝區大小
};
#endif // SERIALPORT_H
對應 cpp:
函數初始化:
SerialPort::SerialPort(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::SerialPort)
{
ui->setupUi(this);
this->setWindowTitle(tr("串口調試助手 Qt版 V1.0"));
this->setFixedSize(this->width(), this->height());
m_nRecvNum = 0;
m_nSendNum = 0;
m_bOpen = false;
InitStatusBar();
InitCommCmb();
ui->OnOffBtn->setIcon(QIcon(":/pic/res/OFF.png"));
ui->RecvDataEdt->setReadOnly(true);
m_serial = new QSerialPort;
connect(m_serial, SIGNAL(readyRead()), this, SLOT(slot_RecvPortData()));
m_nReadBuffSize = 64;
}
InitStatusBar() 初始化狀態欄:
void SerialPort::InitStatusBar()
{
m_SerStateLbl = new QLabel();
m_RecvNumLbl = new QLabel();
m_SendNumLbl = new QLabel();
m_ResetNumBtn = new QPushButton();
connect(m_ResetNumBtn, SIGNAL(clicked()), this, SLOT(slot_ResetNumBtn_clicked()));
m_SerStateLbl->setMinimumSize(180, 20);
m_RecvNumLbl->setMinimumSize(180, 20); // 標籤最小尺寸
m_SendNumLbl->setMinimumSize(180, 20);
ui->statusBar->addWidget(m_SerStateLbl);
ui->statusBar->addWidget(m_RecvNumLbl);
ui->statusBar->addWidget(m_SendNumLbl);
ui->statusBar->addWidget(m_ResetNumBtn);
SetSerState();
SetRecvNum();
SetSendNum();
m_ResetNumBtn->setText(tr("復位計數"));
}
其中對應的set個個的函數:
void SerialPort::SetSerState()
{
QString strState;
if ( m_bOpen )
strState = tr("打開");
else
strState = tr("關閉");
m_SerStateLbl->setText(tr("串口狀態:%1").arg(strState));
}
void SerialPort::SetRecvNum()
{
QString strRecvNum = QString::number(m_nRecvNum);
m_RecvNumLbl->setText(tr("接收字節數:%1").arg(strRecvNum));
}
void SerialPort::SetSendNum()
{
QString strSendNum = QString::number(m_nSendNum);
m_SendNumLbl->setText(tr("發送字節數:%1").arg(strSendNum));
}
其目的在狀態欄上顯示對應的接收數據,並顯示在狀態欄上面。
InitCommCmb() 初始化CombBox
void SerialPort::InitCommCmb()
{
SetPortNumCmb(); // 串口號
SetBaudCmb(); // 波特率
SetDPaityCmb(); // 校驗位
SetDataBCmb(); // 數據位
SetStopBCmb(); // 停止位
SetStreamCmb(); // 流控制
}
這些函數是初始化最基本的東西:串口號,波特率,校驗位,數據位,停止位,流控制(這個用的較少)
// 設置串口號
void SerialPort::SetPortNumCmb()
{
QStringList commPortList = GetEnableCommPortQt();
if ( !commPortList.isEmpty() )
ui->PortNumCmb->addItems(commPortList);
}
// 獲取計算機可用串口 QSerialPort QSerialPortInfo類
QStringList SerialPort::GetEnableCommPortQt()
{
QStringList CommPortList;
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
QSerialPort serial;
serial.setPort(info);
if (serial.open(QIODevice::ReadWrite))
{
CommPortList.append(serial.portName());
serial.close();
}
}
return CommPortList;
}
這個可以尋找當前串口號,然後添加到對應的選項框。
波特率:
// 設置波特率
void SerialPort::SetBaudCmb()
{
QStringList baudRList;
baudRList.append(tr("110"));
baudRList.append(tr("300"));
baudRList.append(tr("600"));
baudRList.append(tr("1200"));
baudRList.append(tr("2400"));
baudRList.append(tr("4800"));
baudRList.append(tr("9600"));
baudRList.append(tr("14400"));
baudRList.append(tr("19200"));
baudRList.append(tr("38400"));
baudRList.append(tr("56000"));
baudRList.append(tr("57600"));
baudRList.append(tr("115200"));
baudRList.append(tr("128000"));
baudRList.append(tr("256000"));
baudRList.append(tr("自定義"));
ui->baudRCmb->addItems(baudRList);
ui->baudRCmb->setCurrentIndex(6);
}
校驗位
void SerialPort::SetDPaityCmb()
{
QStringList DPaityList;
DPaityList.append(tr("NONE"));
DPaityList.append(tr("ODD"));
DPaityList.append(tr("EVEN"));
DPaityList.append(tr("MARK"));
DPaityList.append(tr("SPACE"));
ui->DPaityCmb->addItems(DPaityList);
}
數據位:
// 設置數據位
void SerialPort::SetDataBCmb()
{
for (int i = 5; i <= 8; i++)
{
QString strDataB = QString::number(i);
ui->DataBCmb->addItem(strDataB);
}
ui->DataBCmb->setCurrentIndex(3);
}
停止位
// 設置停止位
void SerialPort::SetStopBCmb()
{
ui->StopBCmb->addItem(tr("1"));
ui->StopBCmb->addItem(tr("1.5"));
ui->StopBCmb->addItem(tr("2"));
}
流控制:
// 流控制
void SerialPort::SetStreamCmb()
{
ui->FlowCtrlCmb->addItem(tr("NO"));
ui->FlowCtrlCmb->addItem(tr("RTS/CTS"));
ui->FlowCtrlCmb->addItem(tr("XON/XOFF"));
}
初始化結束後,我們開始第二歩:
打開串口
// 打開/關閉串口
void SerialPort::on_OnOffBtn_clicked()
{
if (m_serial->isOpen()) // 已經處於打開狀態,則關閉串口
{
m_serial->close();
ui->OnOffBtn->setText(tr("打開"));
ui->OnOffBtn->setIcon(QIcon(":/pic/res/OFF.png"));
m_bOpen = false;
SetSerState();
}
else // 串口處於關閉狀態,打開串口
{
if ( !SetSerialPortParam(m_serial) )
{
QMessageBox::critical(this, tr("Error"), tr("串口錯誤!"), QMessageBox::Ok);
return;
}
// 打開串口
if ( !m_serial->open(QIODevice::ReadWrite) ) // 打開失敗
{
QMessageBox::critical(this, tr("Error"), tr("串口不存在或者被其它程序佔用!"), QMessageBox::Ok);
// QString strRecv = ui->RecvDataEdt->toPlainText();
// strRecv += tr("\n【Error】Can't Open COM Port!");
ui->RecvDataEdt->append(tr("\n【Error】Can't Open COM Port!"));
return;
}
// 設置串口緩衝區大小
m_serial->setReadBufferSize(m_nReadBuffSize);
ui->OnOffBtn->setText(tr("斷開"));
ui->OnOffBtn->setIcon(QIcon(":/pic/res/ON.png"));
m_bOpen = true;
SetSerState();
}
}
// 設置串口參數,失敗返回false,成功返回true
bool SerialPort::SetSerialPortParam(QSerialPort *serial)
{
// 設置串口號
QString strPortNum = ui->PortNumCmb->currentText();
if (strPortNum == tr(""))
return false;
serial->setPortName(strPortNum);
// 設置波特率
qint32 nBaudRate = ui->baudRCmb->currentText().toInt();
serial->setBaudRate(nBaudRate);
// 設置奇偶校驗
int nParityType = ui->DPaityCmb->currentIndex();
switch (nParityType)
{
case 0:
serial->setParity(QSerialPort::NoParity);
break;
case 1:
serial->setParity(QSerialPort::OddParity);
break;
case 2:
serial->setParity(QSerialPort::EvenParity);
break;
case 3:
serial->setParity(QSerialPort::MarkParity);
break;
case 4:
serial->setParity(QSerialPort::SpaceParity);
break;
default:
serial->setParity(QSerialPort::UnknownParity);
break;
}
// 設置數據位
int nDataBits = ui->DataBCmb->currentIndex();
switch (nDataBits)
{
case 0:
serial->setDataBits(QSerialPort::Data5);
break;
case 1:
serial->setDataBits(QSerialPort::Data6);
break;
case 2:
serial->setDataBits(QSerialPort::Data7);
break;
case 3:
serial->setDataBits(QSerialPort::Data8);
break;
default:
serial->setDataBits(QSerialPort::UnknownDataBits);
break;
}
// 設置停止位
int nStopBits = ui->StopBCmb->currentIndex();
switch (nStopBits)
{
case 0:
serial->setStopBits(QSerialPort::OneStop);
break;
case 1:
serial->setStopBits(QSerialPort::OneAndHalfStop);
break;
case 2:
serial->setStopBits(QSerialPort::TwoStop);
break;
default:
serial->setStopBits(QSerialPort::UnknownStopBits);
break;
}
// 流控制
int nFlowCtrl = ui->FlowCtrlCmb->currentIndex();
switch (nFlowCtrl)
{
case 0:
serial->setFlowControl(QSerialPort::NoFlowControl);
break;
case 1:
serial->setFlowControl(QSerialPort::HardwareControl);
break;
case 2:
serial->setFlowControl(QSerialPort::SoftwareControl);
break;
default:
serial->setFlowControl(QSerialPort::UnknownFlowControl);
break;
}
return true;
}
發送數據,接收數據:
// 槽函數,接收串口數據
void SerialPort::slot_RecvPortData()
{
QByteArray bytes = m_serial->readAll();
if ( !bytes.isEmpty() )
{
QString strRecv = QString::fromLocal8Bit(bytes);
ui->RecvDataEdt->append(strRecv);
m_nRecvNum += bytes.count();
SetRecvNum();
}
else
ui->RecvDataEdt->setText(tr("接收數據出錯!"));
}
// 發送數據,寫串口
void SerialPort::on_SendBtn_clicked()
{
// 串口未打開
if ( !m_bOpen )
{
QMessageBox::warning(this, tr("Error"), tr("串口未打開,發送失敗!"), QMessageBox::Ok);
return;
}
QByteArray SendBytes = ui->SendDataEdt->toPlainText().toLocal8Bit();
if ( !SendBytes.isEmpty() )
{
m_serial->write(SendBytes);
m_nSendNum += SendBytes.count();
SetSendNum();
}
}
這裏如果想顯示16進制,可以把代碼給爲下面:
QByteArray buffer = tcpClient->readAll();
int length = buffer.count();
if(!buffer.isEmpty())
{
for(int i = 0; i<length; i++)
{
ui->textEdit_2->append(QString::asprintf("%0.2X ",buffer.at(i)));
}
// ui->textEdit_2->append(buffer.toHex()); //16進制顯示出來數據
}
這樣輸出的就是大寫的16進制的數據啦。
其他槽函數
// 串口關閉事件,如果窗口關閉前串口未關閉,則關閉串口
void SerialPort::closeEvent(QCloseEvent *event)
{
if (m_serial->isOpen())
m_serial->close();
event->accept();
}
// 波特率自定義
void SerialPort::on_baudRCmb_currentIndexChanged(int index)
{
uint nCount = ui->baudRCmb->count();
if ((unsigned)index == nCount - 1)
{
ui->baudRCmb->setEditable(TRUE);
ui->baudRCmb->setItemText(index, tr(""));
}
else
{
ui->baudRCmb->setEditable(FALSE);
ui->baudRCmb->setItemText(nCount-1, tr("自定義"));
}
}
// 刷新串口
void SerialPort::on_ReflushSerPortBtn_clicked()
{
ui->PortNumCmb->clear();
SetPortNumCmb();
}
// 復位計數
void SerialPort::slot_ResetNumBtn_clicked()
{
m_nSendNum = 0;
m_nRecvNum = 0;
SetSendNum();
SetRecvNum();
}
// 清空接受區
void SerialPort::on_ClearRecvBtn_clicked()
{
ui->RecvDataEdt->setText(tr(""));
}
需要例子的可以私信我,關注我。