很多小伙伴们对串口编程刚上手时,不知道如何下手,本例子带大家看看一个简单的串口通讯的例子,例子是网上的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(""));
}
需要例子的可以私信我,关注我。