1.添加源码到工程
将qextserialport-1.2rc.zip解压,将解压后的src目录拷贝到项目里的子目录SerialSrc下,在项目pro文件中增加下面这行
include(./serialSrc/src/qextserialport.pri)
2.编译时,显示 'DEVICE_NOTIFY_ALL_INTERFACE_CLASSES'未定义
解决:
修改qextserialenumerator_p.h文件,将0x0500修改为0x0501,解决window下编译提示“DEVICE_NOTIFY_ALL_INTERFACE_CLASSES”未定义错误。
3.读取在线串口
包含头文件:
#include "qextserialport.h"
#include "qextserialenumerator.h"
示例:
QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();
//! [1]
qDebug() << "List of ports:";
//! [2]
foreach (QextPortInfo info, ports) {
qDebug() << "port name:" << info.portName; //COMID
qDebug() << "friendly name:" << info.friendName; //名称
qDebug() << "physical name:" << info.physName;
qDebug() << "enumerator name:" << info.enumName;
qDebug() << "vendor ID:" << info.vendorID;
qDebug() << "product ID:" << info.productID;
qDebug() << "===================================";
}
打印:
4.串口库相关使用(参考example示例)
串口有两种模式EventDriven/Polling
EventDriven(事件驱动方式)
使用事件处理串口的读取,一旦有数据到来,就会发出readyRead()信号,我们可以关联该信号来读取串口的数据。在事件驱动的方式下,串口的读写是异步的,调用读写函数会立即返回,它们不会冻结调用线程。
Polling (查询方式)
读写函数是同步执行的,信号不能工作在这种模式下,而且有些功能也无法实现。但是这种模式下的开销较小。我们需要自己建立定时器来读取串口的数据。
在Windows下支持以上两种模式,而在Linux下只支持Polling模式。
读取方式
如果想读取一行有效数据时:
if(port->canReadLine())
{
qDebug()<<port->readLine();
}
如果想读取所有有效数据时:
if (port->bytesAvailable()) {
qDebug()<<port->readAll();
}
QextSerialPort类
用来描述具体的一个端口,可以通过它的成员函数,来获取/设置该端口的波特率,名称,停止位等,也可以通过该类来打开/关闭某个端口
示例:
port->setPortName("COM1"); // port是个QextSerialPort类对象
port->setBaudRate(BAUD1152000 );
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(StopBitsType);
port->setQueryMode(EventDriven); //设置事件驱动模式
port->setBaudRate((BaudRateType)ui->baudRateBox->itemData(idx).toInt());
port->open(QIODevice::ReadWrite); //打开串口
//进行操作中... ...
port->close(); //关闭串口
QextSerialEnumerator类
用来统计在线串口用的,它有个成员函数getPorts(),其中上面第3节时便用到了.
它有两个信号函数:
deviceDiscovered(const QextPortInfo &info);
//出现有新的串口时,会触发该信号,并将出现的串口信息存到info参数中
deviceRemoved(const QextPortInfo &info);
//当某个串口消失时,会触发该信号,并将消失的串口信息存到info参数中
注意:上面两个信号函数默认是不会触发的,需要调用setUpNotifications()成员函数来开启信号事件触发
5.示例-使用EventDriven事件驱动模式制作串口助手
5.1 效果图-跟下位机通信
和原子的XCOM串口助手做比较
5.2创建UI
5.3 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui>
#include "qextserialport.h"
#include "qextserialenumerator.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
QextSerialPort *port; //端口,用来描述具体的一个端口
QextSerialEnumerator *enumerator; //在线串口统计类
protected:
void closeEvent(QCloseEvent *);
void initBtn(); //初始化按钮
void initComboBoxs(); //初始化下拉列表框
void initSerial(); //初始化串口
void Change_btn_isOn(bool ison);
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_btn_send_clicked(); //发送数据
void on_betn_clear_clicked(); //清除接收数据
void on_btn_switch_clicked(); //串口开关
void onPortAddedOrRemoved(); //刷新串口号
void readLineData(); //读数据
void on_serial_name_currentIndexChanged(int index);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
5.4 源文件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle(("简易串口工具"));
ui->recvEdit->setReadOnly(true);
initBtn();
initComboBoxs();
initSerial();
qApp->setStyleSheet("QComboBox::item{text-align: center; }");
}
void Widget::initBtn() //初始化按钮
{
Change_btn_isOn(false);
}
void Widget::initComboBoxs() //初始化下拉列表框
{
BaudRateType RateTypes[12]={
BAUD1200,BAUD2400 ,BAUD4800,BAUD9600 ,
BAUD14400,BAUD19200,BAUD38400,BAUD56000,
BAUD57600,BAUD115200,BAUD128000, BAUD256000};
DataBitsType BitsTypes[4]={DATA_5,DATA_6, DATA_7, DATA_8};
for(int i=0;i<12;i++)
{
ui->serial_baud->addItem(QString("%1").arg((int)RateTypes[i]),RateTypes[i]);
}
for(int i=0;i<4;i++)
{
ui->serial_data->addItem(QString("%1").arg((int)BitsTypes[i]),BitsTypes[i]);
}
ui->serial_parity->addItem("无",PAR_NONE);
ui->serial_parity->addItem("奇校验",PAR_ODD);
ui->serial_parity->addItem("偶校验",PAR_EVEN);
ui->serial_stop->addItem("1",STOP_1);
ui->serial_stop->addItem("1.5",STOP_1_5);
ui->serial_stop->addItem("2",STOP_2);
}
void Widget::initSerial() //初始化串口
{
onPortAddedOrRemoved();
enumerator = new QextSerialEnumerator();
enumerator->setUpNotifications();
connect(enumerator, SIGNAL(deviceDiscovered(QextPortInfo)),this, SLOT(onPortAddedOrRemoved())); //发现有串口
connect(enumerator, SIGNAL(deviceRemoved(QextPortInfo)), this, SLOT(onPortAddedOrRemoved())); //发现没有串口了
port = new QextSerialPort(QextSerialPort::EventDriven,this);
connect(port, SIGNAL(readyRead()), this,SLOT(readLineData())); //连接信号
}
void Widget::on_btn_send_clicked() //发送数据
{
if (port->isOpen() && !ui->sendEdit->toPlainText().isEmpty())
{
QString data = ui->sendEdit->toPlainText();
data+="\r\n";
}
}
void Widget::on_betn_clear_clicked()//清除接收数据
{
ui->recvEdit->clear();
}
void Widget::on_btn_switch_clicked()//串口开关
{if(!port->isOpen()) //当前未打开
{
Change_btn_isOn(true);
port->setPortName(ui->serial_name->itemData(ui->serial_name->currentIndex()).toString());
port->setBaudRate((BaudRateType)ui->serial_baud->itemData(ui->serial_baud->currentIndex()).toInt());
port->setDataBits((DataBitsType)ui->serial_data->itemData(ui->serial_data->currentIndex()).toInt());
port->setParity((ParityType)ui->serial_parity->itemData(ui->serial_parity->currentIndex()).toInt());
port->setStopBits((StopBitsType)ui->serial_stop->itemData(ui->serial_stop->currentIndex()).toInt());
port->open(QIODevice::ReadWrite);
}
else
{
Change_btn_isOn(false);
port->close();
}
}
void Widget::closeEvent(QCloseEvent *)
{
if(port->isOpen())
port->close();
}
void Widget::readLineData() //读数据
{
while(port->canReadLine()) {
ui->recvEdit->moveCursor(QTextCursor::End);
ui->recvEdit->insertPlainText(QString::fromLocal8Bit(port->readLine()));
}
}
void Widget::onPortAddedOrRemoved() //刷新串口号
{
QString current = ui->serial_name->currentText();
ui->serial_name->blockSignals(true); //阻塞信号
ui->serial_name->clear();
foreach (QextPortInfo info, QextSerialEnumerator::getPorts())
{
QString friendname = info.friendName;
int end=friendname.lastIndexOf(" ");
if(end!=-1)
{
ui->serial_name->addItem(QString("%1:%2").arg(info.portName).arg(info.friendName.left(end)),info.portName);
}
else
{
ui->serial_name->addItem(QString("%1:%2").arg(info.portName).arg(info.friendName),info.portName);
}
}
ui->serial_name->setCurrentIndex(ui->serial_name->findText(current));
if(ui->serial_name->currentIndex()==-1)
ui->serial_name->setCurrentIndex(0);
ui->serial_name->blockSignals(false); //关闭阻塞
}
void Widget::Change_btn_isOn(bool ison)
{
if(!ison)
{
ui->btn_switch->setStyleSheet("color:blue;border: 1px solid blue");
ui->btn_switch->setText("打开串口");
}
else
{
ui->btn_switch->setStyleSheet("color:red;border: 1px solid red");
ui->btn_switch->setText("关闭串口");
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_serial_name_currentIndexChanged(int index)
{
if (port->isOpen()) { //如果是开启的,则关闭串口
port->close();
Change_btn_isOn(false);
}
}