QT for Android 之低功耗蓝牙

一、新建工程,自定义创建路径与名称,这边自定义ble0507,然后按照         下方步骤一直点next,直至完成。

二、先在.pro文件中 添加蓝牙模块bluetooth

三、设计UI界面并命名其控件名称

四、在widget.h文件中 添加头文件并声明定义

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include <QBluetoothDeviceDiscoveryAgent>       //设备搜寻
#include <QBluetoothLocalDevice>                //本地设备信息
#include <QMessageBox>                          //对话框
#include <QLowEnergyController>                 //设备连接
#include <QLowEnergyService>                    //数据接收、发送
#include <QScrollBar>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    QBluetoothLocalDevice *localDevice;        //获取本地设备的蓝牙状态信息
    QBluetoothDeviceDiscoveryAgent *deviceDiscoveryAgent;   //搜索周围蓝牙设备
    QBluetoothDeviceInfo deviceInfo;            //保存需要连接的设备的信息
    QLowEnergyController *m_controller;         //用于蓝牙设备连接
    QLowEnergyService *m_service;               //用于数据接收与发送
    QLowEnergyCharacteristic m_readCharacteristic;      //“读”服务特性
    QLowEnergyCharacteristic m_writeCharacteristic[5];  //“写”服务特性
    QLowEnergyService::WriteMode m_writeMode;           //“写”特性模式
    QLowEnergyDescriptor m_notificationDesc;            //用于存储BLE描述符信息
    int sendMode;
    int sendSelect;

private slots:
    void on_pushButton_open_pressed();

    void on_pushButton_search_pressed();
    void addBlueToothList(const QBluetoothDeviceInfo &info);

    void on_pushButton_connect_pressed();
    void BlueServiceDiscovered(const QBluetoothUuid &gatt);
    void BlueServiceScanDone();
    void searchCharacteristic();
    void BlueDeviceConnected();
    void BlueDeviceDisconnected();
    void BleServiceServiceStateChanged(QLowEnergyService::ServiceState s);

    void BleServiceCharacteristicChanged(const QLowEnergyCharacteristic &c, const QByteArray &value);
    void on_pushButton_disconnect_pressed();

    void on_pushButton_send_pressed();

    void on_pushButton_clean_pressed();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

五、在widget.cpp中 

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);



    //实例化蓝牙相关对象
    deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent();
    localDevice = new QBluetoothLocalDevice();

    //初始化
    m_controller=NULL;
    m_service=NULL;
    sendSelect=1;
    sendMode=0;

    //设置显示本地蓝牙名称
    QString label_name("本地蓝牙:");
    label_name += localDevice->name();
    ui->label_blename->setText(label_name);

    //关联发现设备的槽函数,当扫描发现周围的蓝牙设备时,会发出deviceDiscovered信号
    connect(deviceDiscoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this,SLOT(addBlueToothList(QBluetoothDeviceInfo)));

    //自动打开蓝牙
    if(localDevice ->hostMode() == QBluetoothLocalDevice::HostPoweredOff)
    {
        localDevice->powerOn();
    }
}

Widget::~Widget()
{
    delete ui;
}


//手动打开蓝牙
void Widget::on_pushButton_open_pressed()
{
    localDevice->powerOn();
}

//搜索蓝牙设备
void Widget::on_pushButton_search_pressed()
{
    ui->comboBox_name->clear();
    deviceDiscoveryAgent->start();
    QMessageBox::information(this,"提示","正在搜索中...");
}
//当搜索到周围的设备时会调用当前的槽函数
void Widget::addBlueToothList(const QBluetoothDeviceInfo &info)
{
    QString label= QString("%1 %2").arg(info.address().toString()).arg(info.name());
    ui->comboBox_name->addItem(label); //添加字符串到comboBox上
}

//断开蓝牙设备
void Widget::on_pushButton_disconnect_pressed()
{
    QMessageBox::StandardButton result = QMessageBox::information(this,"连接提示","是否断开蓝牙?",QMessageBox::Yes|QMessageBox::No);
    if(result == QMessageBox::Yes)
    {
        if(m_controller)
        {
            delete m_controller;
            m_controller = NULL;
        }
        QMessageBox::information(this,"提示","已成功断开蓝牙!");
    }
}

//发送信息
void Widget::on_pushButton_send_pressed()
{
    QString text=ui->lineEdit_send->text();
    QByteArray array=text.toLocal8Bit();
    /*写入newValue作为特性的值。
    如果操作成功,将发射characteristicWritten()信号;
    低功耗设备: 每次最多写20个字节*/
    m_service->writeCharacteristic(m_writeCharacteristic[sendSelect],array, m_writeMode);
}

//清除数据
void Widget::on_pushButton_clean_pressed()
{
    ui->textEdit_receive->clear();
}

//连接蓝牙
void Widget::on_pushButton_connect_pressed()
{
    QString text = ui->comboBox_name->currentText();
    int index = text.indexOf(' ');
    if(index == -1) return;
    QBluetoothAddress address(text.left(index));
    QString connect_device="是否开始连接蓝牙设备:\n";
    connect_device+=ui->comboBox_name->currentText();
    QMessageBox::StandardButton result2 = QMessageBox::information(this,tr("连接提示"),connect_device,QMessageBox::Yes|QMessageBox::No);
    /*低功耗蓝牙设备*/
    if(result2 == QMessageBox::Yes)
    {
        if(m_controller!=NULL)
        {
            m_controller->disconnectFromDevice(); //断开远程设备
            delete m_controller;
            m_controller= NULL;
        }
        QList<QBluetoothDeviceInfo> info_list=deviceDiscoveryAgent->discoveredDevices(); //得到扫描的所有设备信息
        for(int i=0;i<info_list.count();i++)
        {
            if(info_list.at(i).address().toString()==text.left(index))
            {
                deviceInfo=info_list.at(i);
                break;
            }
        }
        //创建中央角色设备
        m_controller= new QLowEnergyController(deviceInfo, this);
        //m_control=QLowEnergyController::createCentral(remoteDevice,this);
        if(m_controller==0)
        {
            QMessageBox::critical(this,"警告","创建中央角色设备失败!");
        }
        else
        {
//            ui->plainTextEdit->insertPlainText("创建中央角色设备成功!\n");
        }
        //每次发现新的服务就会发送此信号
        connect(m_controller, SIGNAL(serviceDiscovered(QBluetoothUuid)),this, SLOT(BlueServiceDiscovered(QBluetoothUuid)));
        //正在运行的服务发现完成时发出此信号。
        connect(m_controller, SIGNAL(discoveryFinished()),this, SLOT(BlueServiceScanDone()));
        //当控制器成功连接到远程Low Energy设备时,会发出此信号。
        connect(m_controller, SIGNAL(connected()),this, SLOT(BlueDeviceConnected()));
        //当控制器从远程低功耗设备断开时发出此信号。
        connect(m_controller, SIGNAL(disconnected()),this, SLOT(BlueDeviceDisconnected()));
        //该信号在发生错误时发出。
        connect(m_controller, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
                [=](QLowEnergyController::Error error){
            if(error==QLowEnergyController::NoError)
            {
//                ui->plainTextEdit->insertPlainText("没有发生错误\n");
            }
            else if(error==QLowEnergyController::UnknownError)
            {
//                ui->plainTextEdit->insertPlainText("出现未知错误。\n");
                QMessageBox::critical(this,"警告","出现未知错误!");
            }
            else if(error==QLowEnergyController::UnknownRemoteDeviceError)
            {
//                ui->plainTextEdit->insertPlainText("无法找到传递给此类构造函数的远程Bluetooth Low Energy设备。\n");
                QMessageBox::critical(this,"警告","无法找到传递给此类构造函数的远程Bluetooth Low Energy设备!");
            }
            else if(error==QLowEnergyController::NetworkError)
            {
//                ui->plainTextEdit->insertPlainText("尝试读取或写入远程设备失败\n");
                QMessageBox::critical(this,"警告","尝试读取或写入远程设备失败!");
            }
            else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
            {
//                ui->plainTextEdit->insertPlainText("传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备\n");
                QMessageBox::critical(this,"警告","传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备!");
            }
            else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
            {
//                ui->plainTextEdit->insertPlainText("尝试连接到远程设备失败。\n");
                QMessageBox::critical(this,"警告","尝试连接到远程设备失败!");
            }
            else
//            ui->plainTextEdit->insertPlainText("*****未知错误!******\n");
                QMessageBox::critical(this,"警告","*****未知错误!******");
        });
        //连接到远程蓝牙低功耗设备。
        m_controller->connectToDevice();
    }
}
//每次发现新的服务,就会调用该槽函数
void Widget::BlueServiceDiscovered(const QBluetoothUuid &gatt)
{
    ui->textEdit_receive->insertPlainText(gatt.toString()+"\n");
}
/*默认指定的UUID服务*/
static const QLatin1String serviceUuid("{0000ffe0-0000-1000-8000-00805F9B34FB}");
//正在运行的服务发现完成时发出信号
void Widget::BlueServiceScanDone()
{
    //判断之前有没有连接过
    if(m_service != NULL)
    {
        delete m_service;
        m_service = NULL;
    }

    ui->textEdit_receive->insertPlainText("选中的服务:\n"+serviceUuid);

    //与设备之间建立服务
    m_service = m_controller ->createServiceObject(QBluetoothUuid(serviceUuid),this);

    if(m_service == NULL)
    {
        ui->textEdit_receive->insertPlainText("服务建立失败!");
        return;
    }
    else
    {
        ui->textEdit_receive->insertPlainText("服务建立成功!");
    }
    //服务状态改变时发出此信号
    connect(m_service,SIGNAL(stateChanged(QLowEnergyService::ServiceState)),this,SLOT(BleServiceServiceStateChanged(QLowEnergyService::ServiceState)));
    //特性值由事件改变时发出此信号在外设上。newValue参数包含更新后的值特性
    connect(m_service,SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),this,SLOT(BleServiceCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));
    //错误信号
    connect(m_service,static_cast<void (QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error),
            [=](QLowEnergyService::ServiceError newErrorr)
    {
        if(newErrorr == QLowEnergyService::NoError)
        {
            ui->textEdit_receive->insertPlainText("没有发生错误!\n");
            ui->textEdit_receive->ensureCursorVisible();
        }
        if(newErrorr == QLowEnergyService::OperationError)
        {
            ui->textEdit_receive->insertPlainText("错误:当服务没有准备好时尝试进行操作!\n");
            ui->textEdit_receive->ensureCursorVisible();
        }
        if(newErrorr == QLowEnergyService::CharacteristicReadError)
        {
            ui->textEdit_receive->insertPlainText("尝试读取特征值失败!\n");
            ui->textEdit_receive->ensureCursorVisible();
        }
        if(newErrorr == QLowEnergyService::CharacteristicWriteError)
        {
            ui->textEdit_receive->insertPlainText("尝试为特性写入新值失败!\n");
            ui->textEdit_receive->ensureCursorVisible();
        }
        if(newErrorr == QLowEnergyService::DescriptorReadError)
        {
            ui->textEdit_receive->insertPlainText("尝试读取描述符值失败\n");
            ui->textEdit_receive->ensureCursorVisible();
        }
        if(newErrorr == QLowEnergyService::DescriptorWriteError)
        {
            ui->textEdit_receive->insertPlainText("尝试向描述符写入新值失败!\n");
            ui->textEdit_receive->ensureCursorVisible();
        }
        if(newErrorr == QLowEnergyService::UnknownError)
        {
            ui->textEdit_receive->insertPlainText("与服务交互时发生未知错误!\n");
            ui->textEdit_receive->ensureCursorVisible();
        }
    });

    if(m_service ->state() == QLowEnergyService::DiscoveryRequired)
    {
        m_service ->discoverDetails();  //启动服务扫描
    }
    else
        searchCharacteristic();
}
//搜索特性
void Widget::searchCharacteristic()
{
    if(m_service)
    {
        QList<QLowEnergyCharacteristic> list = m_service ->characteristics();
        //characteristic  获取详细特性

        sendMode = list.count();     //设置模式选择上限
        for (int i = 0; i < list.count(); i++)
        {
            QLowEnergyCharacteristic c = list.at(i);

            //如果QLowEnergyCharacteristic对象有效,则返回true,否则返回false
            if( c.isValid())
            {
                //返回特征的属性
                //这些属性定义了特征的访问权限
                if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)
                {
                    ui->textEdit_receive->insertPlainText("具有写权限!\n");
                    m_writeCharacteristic[i] = c;   //保存写权限特性
                    if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
                        //如果使用此模式写入特性,则远程外设不应发送写入确认。
                        //无法确定操作的成功,并且有效负载不得超过20个字节。
                        //一个特性必须设置QLowEnergyCharacteristic::WriteNoResponse属性来支持这种写模式。
                        //他的优点是更快的写入操作,因为它可能发生在其他设备交互之间。
                        m_writeMode = QLowEnergyService::WriteWithoutResponse;
                    else
                        m_writeMode = QLowEnergyService::WriteWithResponse;
                    //如果使用此模式写入特性,则外设应发送确认。
                    //如果操作成功,则通过characteristicWritten()信号发出确认。
                    //否则,发出CharacteristicWriteError。
                    //一个特性必须设置QLowEnergyCharacteristic::Write属性来支持这种写模式。
                }
                if(c.properties() & QLowEnergyCharacteristic::Read)
                {
                    m_readCharacteristic = c;   //保存读权限特性
                }

                //描述符定义特征如何由特定客户端配置
                m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);

                //值为真
                if(m_notificationDesc.isValid())
                {
                    //写描述符
                    m_service ->writeDescriptor(m_notificationDesc,QByteArray::fromHex("0100"));
                    ui->textEdit_receive->insertPlainText("写描述符!\n");
                }
            }
        }
    }
}
//当控制器成功连接到远程Low Energy设备时,会发出此信号。
void Widget::BlueDeviceConnected()
{
    //启动发现服务Service
    m_controller->discoverServices();
}
//当控制器从远程低功耗设备断开此信号。
void Widget::BlueDeviceDisconnected()
{
    ui->textEdit_receive->insertPlainText("成功断开!\n");
}
//服务状态改变时发出此信号
void Widget::BleServiceServiceStateChanged(QLowEnergyService::ServiceState s)
{
    //所有细节都已同步
    if(s == QLowEnergyService::ServiceDiscovered)
    {
        QMessageBox::information(this,"提示","已成功连接蓝牙!");
        searchCharacteristic();
    }
}

//读取数据
void Widget::BleServiceCharacteristicChanged(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
    ui->textEdit_receive->insertPlainText(QString(value));
    //移动滚动条到底部
    QScrollBar * scrollbar = ui->textEdit_receive->verticalScrollBar();
    if(scrollbar)
    {
        scrollbar -> setSliderPosition(scrollbar ->maximum());
    }
//    if(!value.isEmpty())
//    {
//        QString str = QString(value).toUtf8().data();
//        str += tr(value);
//        if(str.length() > 12040)                             //数据超出最大缓冲区
//        {
//            str.remove(0, str.length() - 12040);             //清除超出的部分
//        }
//        ui->textEdit_receive->insertPlainText(str);
//    }
}

 效果如下:

QT低功耗蓝牙

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值