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

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+="\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);
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏影子

开始食用grpc(之二)

转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9570992.html

6134
来自专栏Seebug漏洞平台

CVE-2017-16943 Exim UAF漏洞分析

作者:Hcamael@知道创宇404实验室 感恩节那天,meh在Bugzilla上提交了一个exim的uaf漏洞:https://bugs.exim.org/s...

4226
来自专栏hrscy

RxSwift - Why

官方建议总是使用 .addDisposableTo(disposeBag) 即使对于简单绑定来说那不是必要的。

1562
来自专栏有刻

Java 小记 — RabbitMQ 的实践与思考

39310
来自专栏Seebug漏洞平台

CVE-2017-16943 Exim UAF漏洞分析

感恩节那天,meh在Bugzilla上提交了一个exim的uaf漏洞:https://bugs.exim.org/show_bug.cgi?id=2199,这周...

4345
来自专栏用户2442861的专栏

关于muduo网络库的注解

http://blog.csdn.net/liuxuejiang158blog/article/details/17056537#comments

1101
来自专栏马洪彪

Java生成条码二维码

一、概述 可用barcode4j或zxing等第三方库,推荐zxing。 barcode4j资料链接:http://barcode4j.sourceforge....

5018
来自专栏Kubernetes

从源码解析kube-scheduler默认的配置

本文作为Kubernetes Scheduler源码分析的番外篇,补充一个方面的分析:从源码层面解析kube-scheduler的默认配置是怎么做的。 从头来看...

3336
来自专栏Java与Android技术栈

Android App安全防范措施的小结

关闭打印的日志,防止日志中的调试信息被看到。如果在网络框架中使用了日志,那就更加需要关闭了。

1102
来自专栏Kubernetes

Linux kernel Namespace源码分析

学习一下linux kernel namespace的代码还是很有必要的,让你对docker容器的namespace隔离有更深的认识。我的源码分析,是基于Lin...

1K8

扫码关注云+社区

领取腾讯云代金券