1.添加源碼到工程html
將qextserialport-1.2rc.zip解壓,將解壓後的src目錄拷貝到項目裏的子目錄SerialSrc下,在項目pro文件中增長下面這行異步
include(./serialSrc/src/qextserialport.pri)函數
2.編譯時,顯示 'DEVICE_NOTIFY_ALL_INTERFACE_CLASSES'未定義工具
解決:ui
修改qextserialenumerator_p.h文件,將0x0500修改成0x0501,解決window下編譯提示「DEVICE_NOTIFY_ALL_INTERFACE_CLASSES」未定義錯誤。this
3.讀取在線串口spa
包含頭文件:線程
#include "qextserialport.h" #include "qextserialenumerator.h"
示例:code
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() << "==================================="; }
打印:htm
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); } }