• 34.QT-qextserialport第三方库制作串口助手(并动态检测在线串口,附带源码)


    qextserialport-1.2rc库下载链接: http://www.pudn.com/Download/item/id/2298532.html

    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+="
    ";
            port->write( data.toLocal8Bit());
          }
    }
    
    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);
        }
    }

     

  • 相关阅读:
    Difference (第k大(二分)+双指针+ST表)+(很多小细节!!!!!) (MINIEYE杯十六届)
    electronvue实现自定义区域拖拽窗口
    PHP 发送短信
    C#VS2017快捷操作(查看方法重载)
    bootstrapdatetimepicker源代码分析
    Linux下的dstat命令详解以及部分参数说明
    《金字塔原理》
    三年职业生涯回顾
    C++_02_类型转换
    C++_03_动态内存与智能指针
  • 原文地址:https://www.cnblogs.com/lifexy/p/9273352.html
Copyright © 2020-2023  润新知