QT开发笔记(USB Bluetooth)

Posted ManGo CHEN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT开发笔记(USB Bluetooth)相关的知识,希望对你有一定的参考价值。

USB Bluetooth

Qt 官方提供了蓝牙的相关类和 API 函数,也提供了相关的例程给我们参考。笔者根据 Qt

官方的例程编写出适合我们 Ubuntu 和正点原子 I.MX6U 开发板的例程。注意 Windows 上不能
使用 Qt 的蓝牙例程,因为底层需要有 BlueZ 协议栈,而 Windows 没有。Windows 可能需要去
移植。笔者就不去探究了。确保我们正点原子 I.MX6U 开发板与 Ubuntu 可用即可,所以大家还
是老实的用 Ubuntu 来开发吧!

资源简介

在正点原子 IMX6U 开发板上虽然没有带板载蓝牙,但是可以外接免驱 USB 蓝牙,直接在

USB 接口插上一个 USB 蓝牙模块就可以进行本章节的实验了。详细请看【正点原子】I.MX6U

用户快速体验 V1.x.pdf 的第 3.29 小节蓝牙测试,先了解蓝牙是如何在 Linux 上如何使用的,切
记先看正点原子快速体验文档,了解用哪种蓝牙芯片,和怎么测试蓝牙的。本 Qt 教程就不再介
绍了。

应用实例

项目简介:Qt 蓝牙聊天。将蓝牙设置成一个服务器,或者用做客户端,连接手机即可通信。

例 06_bluetooth_chat,Qt 蓝牙聊天(难度:难)。项目路径为 Qt/3/06_bluetooth_chat。
Qt 使用蓝牙,需要在项目文件加上相应的蓝牙模块。添加的代码如下红色加粗部分。

06_bluetooth_chat.pro 文件代码如下。

1 QT += core gui bluetooth 

2 

3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 

4 

5 CONFIG += c++11 

6 

7 # The following define makes your compiler emit warnings if you use 

8 # any Qt feature that has been marked deprecated (the exact warnings 

9 # depend on your compiler). Please consult the documentation of the 

10 # deprecated API in order to know how to port your code away from it. 

11 DEFINES += QT_DEPRECATED_WARNINGS 

12 

13 # You can also make your code fail to compile if it uses deprecated APIs. 

14 # In order to do so, uncomment the following line. 

15 # You can also select to disable deprecated APIs only up to a certain 
version of Qt. 

16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the 
APIs deprecated before Qt 6.0.0 

17 

18 SOURCES += \\ 

19 chatclient.cpp \\ 

20 chatserver.cpp \\ 

21 main.cpp \\ 

22 mainwindow.cpp \\ 

23 remoteselector.cpp 

24 

25 HEADERS += \\ 

26 chatclient.h \\ 

27 chatserver.h \\ 

28 mainwindow.h \\

29 remoteselector.h 

30 

31 # Default rules for deployment. 

32 qnx: target.path = /tmp/$$TARGET/bin 

33 else: unix:!android: target.path = /opt/$$TARGET/bin 

34 !isEmpty(target.path): INSTALLS += target 

第 18~29 行,可以看到我们的项目组成文件。一个客户端,一个服务端,一个主界面和一
个远程选择蓝牙的文件。总的看起来有四大部分,下面就介绍这四大部分的文件。
chatclient.h 的代码如下。

 /****************************************************************** 
 Copyright (C) 2015 The Qt Company Ltd. 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 06_bluetooth_chat 
 * @brief chatclient.h 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-03-20 
 *******************************************************************/ 

1 #ifndef CHATCLIENT_H 

2 #define CHATCLIENT_H 

3 

4 #include <qbluetoothserviceinfo.h> 

5 #include <QBluetoothSocket> 

6 #include <QtCore/QObject> 

7 

8 QT_FORWARD_DECLARE_CLASS(QBluetoothSocket) 

9 

10 class ChatClient : public QObject 

11  

12 Q_OBJECT 

13 

14 public: 

15 explicit ChatClient(QObject *parent = nullptr); 

16 ~ChatClient(); 

17 

18 /* 开启客户端 */ 

19 void startClient(const QBluetoothServiceInfo &remoteService); 

20 

21 /* 停止客户端 */ 

22 void stopClient(); 

23 

24 public slots: 

25 /* 发送消息 */ 

26 void sendMessage(const QString &message); 

27 

28 /* 主动断开连接 */ 

29 void disconnect(); 

30 

31 signals: 

32 /* 接收到消息信号 */ 

33 void messageReceived(const QString &sender, const QString &message); 

34 

35 /* 连接信号 */ 

36 void connected(const QString &name); 

37 

38 /* 断开连接信号 */ 

39 void disconnected(); 

40 

41 private slots: 

42 /* 从 socket 里读取消息 */ 

43 void readSocket(); 

44 

45 /* 连接 */ 

46 void connected(); 

47 

48 private: 

49 /* socket 通信 */ 

50 QBluetoothSocket *socket; 

51 ; 

52 

53 #endif // CHATCLIENT_H 

 chatclient.h 文件主要是客户端的头文件,其中写一些接口,比如开启客户端,关闭客户端,
接收信号与关闭信号等等。 
chatclient.cpp 的代码如下。 

 /****************************************************************** 
 Copyright (C) 2015 The Qt Company Ltd. 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 06_bluetooth_chat 
 * @brief chatclient.cpp 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-03-20 
 *******************************************************************/
 1 #include "chatclient.h" 

2 #include <qbluetoothsocket.h> 

3 

4 ChatClient::ChatClient(QObject *parent) 

5 : QObject(parent), socket(0) 

6  

7  

8 

9 ChatClient::~ChatClient() 

10  

11 stopClient(); 

12  

13 

14 /* 开启客户端 */ 

15 void ChatClient::startClient(const QBluetoothServiceInfo 

&remoteService) 

16  

17 if (socket) 

18 return; 

19 

20 // Connect to service 

21 socket = new 
QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol); 

22 qDebug() << "Create socket"; 

23 socket->connectToService(remoteService); 

24 qDebug() << "ConnectToService done"; 

25 

26 connect(socket, SIGNAL(readyRead()), 

27 this, SLOT(readSocket())); 

28 connect(socket, SIGNAL(connected()), 

29 this, SLOT(connected())); 

30 connect(socket, SIGNAL(disconnected()), 

31 this, SIGNAL(disconnected())); 

32  

33 

34 /* 停止客户端 */ 

35 void ChatClient::stopClient() 

36  

37 delete socket; 

38 socket = 0; 

39  

40 

41 /* 从 Socket 读取消息 */ 
42 void ChatClient::readSocket() 

43  

44 if (!socket) 

45 return; 

46 

47 while (socket->canReadLine())  

48 QByteArray line = socket->readLine(); 

49 emit messageReceived(socket->peerName(), 

50 QString::fromUtf8(line.constData(), 

51 line.length())); 

52  

53  

54 

55 /* 发送的消息 */ 

56 void ChatClient::sendMessage(const QString &message) 

57  

58 qDebug()<<"Sending data in client: " + message; 

59 

60 QByteArray text = message.toUtf8() + '\\n'; 

61 socket->write(text); 

62  

63 

64 /* 主动连接 */ 

65 void ChatClient::connected() 

66  

67 emit connected(socket->peerName()); 

68  

69 

70 /* 主动断开连接*/ 

71 void ChatClient::disconnect()  

72 qDebug()<<"Going to disconnect in client"; 

73 if (socket)  

74 qDebug()<<"diconnecting..."; 

75 socket->close(); 

76  

77  

chatclient.cpp 文件主要是客户端的 chatclient.h 头文件的实现。代码参考 Qt 官方 btchat 例子,
代码比较长,也有相应的注释了,大家自由查看。主要我们关注的是下面的代码。
第 15~32 行,我们需要开启客户端模式,那么我们需要将扫描服务器(手机蓝牙)的结果,
实例化一个蓝牙 socket,使用 socket 连接传入来的服务器信息,即可将本地蓝牙当作客户端,
实现了客户端创建。
chatserver.h 代码如下。

 /****************************************************************** 
 Copyright (C) 2015 The Qt Company Ltd. 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 06_bluetooth_chat 
 * @brief chatserver.h 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-03-20 
 *******************************************************************/ 
 

1 #ifndef CHATSERVER_H 

2 #define CHATSERVER_H 

3 

4 #include <qbluetoothserviceinfo.h> 

5 #include <qbluetoothaddress.h> 

6 #include <QtCore/QObject> 

7 #include <QtCore/QList> 

8 #include <QBluetoothServer> 

9 #include <QBluetoothSocket> 

10 

11 

12 class ChatServer : public QObject 

13  

14 Q_OBJECT 

15 

16 public: 

17 explicit ChatServer(QObject *parent = nullptr); 

18 ~ChatServer(); 

19 

20 /* 开启服务端 */ 

21 void startServer(const QBluetoothAddress &localAdapter = 
QBluetoothAddress()); 

22 

23 /* 停止服务端 */ 

24 void stopServer(); 

25 

26 public slots: 

27 /* 发送消息 */ 

28 void sendMessage(const QString &message); 

29 

30 /* 服务端主动断开连接 */ 

31 void disconnect(); 

32 

33 signals: 
34 /* 接收到消息信号 */ 

35 void messageReceived(const QString &sender, const QString &message); 

36 

37 /* 客户端连接信号 */ 

38 void clientConnected(const QString &name); 

39 

40 /* 客户端断开连接信号 */ 

41 void clientDisconnected(const QString &name); 

42 

43 private slots: 

44 

45 /* 客户端连接 */ 

46 void clientConnected(); 

47 

48 /* 客户端断开连接 */ 

49 void clientDisconnected(); 

50 

51 /* 读 socket */ 

52 void readSocket(); 

53 

54 private: 

55 /* 使用 rfcomm 协议 */ 

56 QBluetoothServer *rfcommServer; 

57 

58 /* 服务器蓝牙信息 */ 

59 QBluetoothServiceInfo serviceInfo; 

60 

61 /* 用于保存客户端 socket */ 

62 QList<QBluetoothSocket *> clientSockets; 

63 

64 /* 用于保存客户端的名字 */ 

65 QList<QString> socketsPeername; 

66 ; 

67 

68 #endif // CHATSERVER_H 

chatserver.h 文件主要是服务端的头文件,其中写一些接口,比如开启服务端,关闭服务端,
接收信号与关闭信号等等。
chatserver.cpp 代码如下。

 /****************************************************************** 
 Copyright (C) 2015 The Qt Company Ltd. 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 06_bluetooth_chat
 * * @brief chatserver.cpp 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-03-20 
 *******************************************************************/ 
 

1 #include "chatserver.h" 

2 

3 #include <qbluetoothserver.h> 

4 #include <qbluetoothsocket.h> 

5 #include <qbluetoothlocaldevice.h> 

6 

7 static const QLatin1String 
serviceUuid("e8e10f95-1a70-4b27-9ccf-02010264e9c8"); 

8 ChatServer::ChatServer(QObject *parent) 

9 : QObject(parent), rfcommServer(0) 

10  

11  

12 

13 ChatServer::~ChatServer() 

14  

15 stopServer(); 

16  

17 

18 /* 开启服务端,设置服务端使用 rfcomm 协议与 serviceInfo 的一些属性 */ 

19 void ChatServer::startServer(const QBluetoothAddress& localAdapter) 

20  

21 if (rfcommServer) 

22 return; 

23 

24 rfcommServer = new 
QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this); 

25 connect(rfcommServer, SIGNAL(newConnection()), this, 
SLOT(clientConnected())); 

26 bool result = rfcommServer->listen(localAdapter); 

27 if (!result)  

28 qWarning()<<"Cannot bind chat server 
to"<<localAdapter.toString(); 

29 return; 

30  

31 
32 

//serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceRecordHandle, 
(uint)0x00010010); 

33 

34 QBluetoothServiceInfo::Sequence classId; 

35 

36 
classId<<QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)
); 

37 
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescrip
torList, 

38 classId); 

39 

40 
classId.prepend(QVariant::fromValue(QBluetoothUuid(serviceUuid))); 

41 

42 serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, 
classId); 

43 
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescrip
torList,classId); 

44 

45 serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, 
tr("Bt Chat Server")); 

46 
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, 

47 tr("Example bluetooth chat server")); 

48 serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, 
tr("qt-project.org")); 

49 

50 serviceInfo.setServiceUuid(QBluetoothUuid(serviceUuid)); 

51 

52 QBluetoothServiceInfo::Sequence publicBrowse; 

53 publicBrowse<< 
QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); 

54 serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, 

55 publicBrowse); 

56 

57 QBluetoothServiceInfo::Sequence protocolDescriptorList; 

58 QBluetoothServiceInfo::Sequence protocol; 

59 protocol<< 
QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)); 

60 protocolDescriptorList.append(QVariant::fromValue(protocol)); 

61 protocol.clear(); 

62 protocol<< 
QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm)) 

63 << 
QVariant::fromValue(quint8(rfcommServer->serverPort())); 

64 protocolDescriptorList.append(QVariant::fromValue(protocol)); 

65 
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, 

66 protocolDescriptorList); 

67 

68 serviceInfo.registerService(localAdapter); 

69  

70 

71 /* 停止服务端 */ 

72 void ChatServer::stopServer() 

73  

74 // Unregister service 

75 serviceInfo.unregisterService(); 

76 

77 // Close sockets 

78 qDeleteAll(clientSockets); 

Qt文档阅读笔记-Bluetooth Scanner Example

这个例子说明了如何找蓝牙设备。

官方给出的文档已经没了,下面我自己补充下。

项目是这样的,主要有2个界面,一个是service,一个是device。刚好对应了2个界面类ServiceDiscoveryDialog和DeviceDiscoveryDialog

首先看下main.cpp

#include "device.h"

#include <QApplication>

int main(int argc, char *argv[])

    QApplication app(argc, argv);

    DeviceDiscoveryDialog d;
    QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));
    d.show();

    app.exec();

    return 0;

入口函数比较简单,就是展示了DeviceDiscoveryDialog界面。

下面是device.h

#ifndef DEVICE_H
#define DEVICE_H

#include "ui_device.h"

#include <qbluetoothlocaldevice.h>

#include <QDialog>

QT_FORWARD_DECLARE_CLASS(QBluetoothDeviceDiscoveryAgent)
QT_FORWARD_DECLARE_CLASS(QBluetoothDeviceInfo)

QT_USE_NAMESPACE

class DeviceDiscoveryDialog : public QDialog

    Q_OBJECT

public:
    DeviceDiscoveryDialog(QWidget *parent = 0);
    ~DeviceDiscoveryDialog();

public slots:
    void addDevice(const QBluetoothDeviceInfo&);
    void on_power_clicked(bool clicked);
    void on_discoverable_clicked(bool clicked);
    void displayPairingMenu(const QPoint &pos);
    void pairingDone(const QBluetoothAddress&, QBluetoothLocalDevice::Pairing);
private slots:
    void startScan();
    void scanFinished();
    void setGeneralUnlimited(bool unlimited);
    void itemActivated(QListWidgetItem *item);
    void hostModeStateChanged(QBluetoothLocalDevice::HostMode);

private:
    QBluetoothDeviceDiscoveryAgent *discoveryAgent;
    QBluetoothLocalDevice *localDevice;
    Ui_DeviceDiscovery *ui;
;

 这里主要想弄懂的是如何使用Qt的蓝牙类,扫描蓝牙的,所以主要关注点在

看下cpp文件里面怎么用的。

DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent)
:   QDialog(parent), localDevice(new QBluetoothLocalDevice),
    ui(new Ui_DeviceDiscovery)

    ui->setupUi(this);

    /*
     * In case of multiple Bluetooth adapters it is possible to set adapter
     * which will be used. Example code:
     *
     * QBluetoothAddress address("XX:XX:XX:XX:XX:XX");
     * discoveryAgent = new QBluetoothDeviceDiscoveryAgent(address);
     *
     **/

    discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
    ......
    connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
            this, SLOT(addDevice(QBluetoothDeviceInfo)));
    ......

从中可以知道,一般情况下使用,如果你电脑里面有多个蓝牙适配器,可以选择用哪个蓝牙适配器进行扫描,如下:

QBluetoothAddress address("XX:XX:XX:XX:XX:XX");
discoveryAgent = new QBluetoothDeviceDiscoveryAgent(address);

如果电脑上只有1个蓝牙,就不用这么麻烦了。可以直接:

discoveryAgent = new QBluetoothDeviceDiscoveryAgent();

 这里对应了1个关键信号,deviceDiscovered。

[signal] void QBluetoothDeviceDiscoveryAgent::deviceDiscovered(const QBluetoothDeviceInfo &info)

简单描述下就是当发现蓝牙设备后,会触发这个信号,并且将发现的设备以QBluetoothDeviceInfo的形式给到槽参数里面。

这个项目,就将槽参数里面的QBluetoothDeviceInfo进行解析

void DeviceDiscoveryDialog::addDevice(const QBluetoothDeviceInfo &info)

    QString label = QString("%1 %2").arg(info.address().toString()).arg(info.name());
    QList<QListWidgetItem *> items = ui->list->findItems(label, Qt::MatchExactly);
    if (items.empty()) 
        QListWidgetItem *item = new QListWidgetItem(label);
        QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(info.address());
        if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus == QBluetoothLocalDevice::AuthorizedPaired )
            item->setTextColor(QColor(Qt::green));
        else
            item->setTextColor(QColor(Qt::black));

        ui->list->addItem(item);
    

还有最后一个更关键的问题怎么触发这个deviceDiscovered,在startScan函数中可以看到。

void DeviceDiscoveryDialog::startScan()

    discoveryAgent->start();
    ui->scan->setEnabled(false);
    ui->inquiryType->setEnabled(false);
void QBluetoothDeviceDiscoveryAgent::start()
Starts Bluetooth device discovery, if it is not already started.
The deviceDiscovered() signal is emitted as each device is discovered. The finished() signal is emitted once device discovery is complete. The discovery utilizes the maximum set of supported discovery methods on the platform.
See also supportedDiscoveryMethods().

当调用QBluetoothDeviceDiscoveryAgent,的start方法后,就会emit2个关键信号,分别是deviceDiscovered()和finished()。

这里跑程序的时候要注意,把电脑的蓝牙打开:

然后就可以Scan了

 

 

以上是关于QT开发笔记(USB Bluetooth)的主要内容,如果未能解决你的问题,请参考以下文章

Qt文档阅读笔记-Bluetooth Scanner Example

Qt文档阅读笔记-Bluetooth Scanner Example

QT开发笔记(Camera)

Hi3516开发笔记:Hi3516虚拟机交叉开发环境搭建之交叉编译Qt

QT学习开发笔记(项目实战之智能家居物联网项目1 )

Qt usb通讯