加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

Qt編程實(shí)例:基于Android的BLE通信軟件

2021/01/11
348
閱讀需 10 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

實(shí)現(xiàn)目標(biāo)

自己編寫基于 Qt 的 Android 軟件,用于實(shí)現(xiàn)手機(jī)與 TB-02-kit 模塊進(jìn)行數(shù)據(jù)通訊;

Android 軟件發(fā)送的數(shù)據(jù),經(jīng) TB-02-kit 模塊轉(zhuǎn)發(fā)至串口助手中輸出;

串口助手發(fā)送的數(shù)據(jù)可以在 Android 軟件中顯示,進(jìn)而實(shí)現(xiàn) BLE 的數(shù)據(jù)雙向通信。

所需工具及環(huán)境

  • TB-02-kit 模塊 Qt Creator 4.10.1Qt 5.13.1XCOM V2.0 串口助手 Android 手機(jī)本人電腦 Windows 10 64bit [版本 10.0.19041.329]

 

前置知識(shí)

給大家介紹一款好用的藍(lán)牙 BT5.0 透?jìng)髂K

Windows 下基于 Qt 開發(fā) Android 應(yīng)用

BLE 中這些概念你都了解嗎

本文源碼

因?yàn)槭堑谝淮畏窒?Qt 代碼,為了方便大家學(xué)習(xí),代碼中添加了大量注釋,大家對(duì)照著代碼學(xué)習(xí)效率高點(diǎn)。

后臺(tái)回復(fù)關(guān)鍵字“Android-BLE”,獲取本文涉及到的軟件及 Qt 工程源碼。

具體實(shí)現(xiàn)

1. 要使用 Qt 藍(lán)牙模塊, 項(xiàng)目的 .pro 文件中要添加聲明才可使用

 

2. 掃描設(shè)備

在構(gòu)造函數(shù)中執(zhí)行藍(lán)牙設(shè)備掃描,即軟件一啟動(dòng)就執(zhí)行掃描。

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

    // 創(chuàng)建搜索服務(wù):https://doc.qt.io/qt-5/qbluetoothdevicediscoveryagent.html
    discoveryAgent =new QBluetoothDeviceDiscoveryAgent(this);
    // 設(shè)置 BLE 的搜索時(shí)間
    discoveryAgent->setLowEnergyDiscoveryTimeout(20000);
    connect(discoveryAgent,SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this,SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo)));// 找到設(shè)備之后添加到列表顯示出來(lái)
    connect(discoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished()));
    connect(discoveryAgent, SIGNAL(canceled()), this, SLOT(scanCanceled()));
    connect(this, SIGNAL(returnAddress(QBluetoothDeviceInfo)), this, SLOT(createCtl(QBluetoothDeviceInfo)));

    // 開始進(jìn)行設(shè)備搜索
    discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
}

 

3. 將掃描結(jié)果添加到 QListWidget 中

//deviceDiscovered signals 對(duì)應(yīng)的槽函數(shù)
void Widget::addBlueToothDevicesToList(const QBluetoothDeviceInfo &info)
{
    if (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)           // 獲取設(shè)備信息,并判斷該設(shè)備是否為 BLE 設(shè)備
    {
        // 格式化設(shè)備地址和設(shè)備名稱
        QString label = QString("%1 %2").arg(info.address().toString()).arg(info.name());
        // 檢查設(shè)備是否已存在,避免重復(fù)添加
        QList items = ui->ctrBleList->findItems(label, Qt::MatchExactly);

        // 不存在則添加至設(shè)備列表
        if (items.empty())
        {
            QListWidgetItem *item = new QListWidgetItem(label);
            ui->ctrBleList->addItem(item);
            devicesList.append(info);
        }
    }
}

 

4. 連接藍(lán)牙,停止掃描

void Widget::on_btnConnectBle_clicked()
{
    // 確認(rèn)選取了某一個(gè)藍(lán)牙設(shè)備
    if(!ui->ctrBleList->currentItem()->text().isEmpty())
    {
        // 獲取選擇的地址
        QString bltAddress = ui->ctrBleList->currentItem()->text().left(17);

        for (int i = 0; i        {
            // 地址對(duì)比
            if(devicesList.at(i).address().toString().left(17) == bltAddress)
            {
                QBluetoothDeviceInfo choosenDevice = devicesList.at(i);
                // 發(fā)送自定義 signals==>執(zhí)行 slots:createCtl
                emit returnAddress(choosenDevice);
                // 停止搜索服務(wù)
                discoveryAgent->stop();
                break;
            }
        }
    }
}

 

5. 獲取特征

void Widget::searchCharacteristic()
{
    if(m_bleServer)
    {
        QList list=m_bleServer->characteristics();
        qDebug()<<"[xiaohage]list.count()="<        // 遍歷 characteristics
        for(int i=0;i        {
            QLowEnergyCharacteristic c=list.at(i);
            /*如果 QLowEnergyCharacteristic 對(duì)象有效,則返回 true,否則返回 false*/
            if(c.isValid())
            {
                // 返回特征的屬性。
                // 這些屬性定義了特征的訪問(wèn)權(quán)限。
                if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)
                {
                    ui->ctrSystemLogInfo->insertPlainText("n 具有寫權(quán)限!");
                    m_writeCharacteristic = c;  // 保存寫權(quán)限特性
                    if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
                    {
                        m_writeMode = QLowEnergyService::WriteWithoutResponse;
                    }
                    else
                    {
                        m_writeMode = QLowEnergyService::WriteWithResponse;
                    }
                }

                if(c.properties() & QLowEnergyCharacteristic::Read)
                {
                    m_readCharacteristic = c; // 保存讀權(quán)限特性
                }

                // 描述符定義特征如何由特定客戶端配置。
                m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
                // 值為真
                if(m_notificationDesc.isValid())
                {
                    // 寫描述符
                    m_bleServer->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100"));
                    ui->ctrSystemLogInfo->insertPlainText("n 寫描述符!");
                }
            }
        }
    }
}

 

6. 發(fā)送數(shù)據(jù)

writeCharacteristic()方法,發(fā)送數(shù)據(jù)給 ble 設(shè)備。

點(diǎn)擊界面中的"發(fā)送"按鈕,發(fā)送"Hello World"字符串。

void Widget::SendMsg(QString text)
{
    QByteArray array=text.toLocal8Bit();

    m_bleServer->writeCharacteristic(m_writeCharacteristic,array, m_writeMode);
}

void Widget::on_btnSendData_clicked()
{
    SendMsg("Hello World");
}

 

7. 寫入數(shù)據(jù)

通過(guò)藍(lán)牙 QLowEnergyService::characteristicRead 的回調(diào)接口,接收藍(lán)牙收到的消息。

void Widget::BleServiceCharacteristicRead(const QLowEnergyCharacteristic &c,const QByteArray &value)
{
    Q_UNUSED(c)

    ui->ctrSystemLogInfo->insertPlainText("n 當(dāng)特征讀取請(qǐng)求成功返回其值時(shí):");
    ui->ctrSystemLogInfo->insertPlainText(QString(value));
}

 

8. 斷開連接

Widget::~Widget()
{
    if(!(m_BLEController->state() == QLowEnergyController::UnconnectedState))
            m_BLEController->disconnectFromDevice();// 從設(shè)備斷開鏈接

    delete ui;
}

 

界面布局

 

結(jié)果展示

如果出現(xiàn)" Cannot connect to remote device. " ,可以點(diǎn)擊"連接"按鈕重新連接一下。

串口助手及應(yīng)用程序輸出

 

To do

本實(shí)例只是演示一下 Android 手機(jī)與 TB-02-kit 模塊的通訊過(guò)程,程序里有需要完善的地方,比如,應(yīng)該增加一個(gè)"掃描"按鈕,而不是軟件啟動(dòng)過(guò)程中直接進(jìn)行藍(lán)牙掃描,這樣的話,就需要藍(lán)牙的上電要在軟件啟動(dòng)之前完成。

程序的健壯性也要完善,比如偶爾會(huì)出現(xiàn)與模塊無(wú)法正常連接的情況,需要再次點(diǎn)擊"連接"按鈕才可,這些工作你們自己可以完善一下哈。

有了本部分知識(shí),下一步我們結(jié)合 Android 手機(jī)和 TB-02-kit 模塊,實(shí)現(xiàn) STM32 的設(shè)備的遠(yuǎn)程控制。

Qt 小知識(shí)

1. Qt Creator 程序輸出窗口過(guò)濾調(diào)試信息

 

2. 為 Button 添加事件

Button 控件右鍵菜單中選中“轉(zhuǎn)到槽 ...”,然后在彈出列表中選中信號(hào):“clicked() ”,然后點(diǎn)擊 OK 按鈕,即可進(jìn)入其事件函數(shù)中。

 

參考資料

Qt 官方文檔:https://doc.qt.io/qt-5/classes.html

谷歌

谷歌

谷歌公司(Google Inc.)成立于1998年9月4日,由拉里·佩奇和謝爾蓋·布林共同創(chuàng)建,被公認(rèn)為全球最大的搜索引擎公司。谷歌是一家位于美國(guó)的跨國(guó)科技企業(yè),業(yè)務(wù)包括互聯(lián)網(wǎng)搜索、云計(jì)算、廣告技術(shù)等,同時(shí)開發(fā)并提供大量基于互聯(lián)網(wǎng)的產(chǎn)品與服務(wù),其主要利潤(rùn)來(lái)自于關(guān)鍵詞廣告等服務(wù)。

谷歌公司(Google Inc.)成立于1998年9月4日,由拉里·佩奇和謝爾蓋·布林共同創(chuàng)建,被公認(rèn)為全球最大的搜索引擎公司。谷歌是一家位于美國(guó)的跨國(guó)科技企業(yè),業(yè)務(wù)包括互聯(lián)網(wǎng)搜索、云計(jì)算、廣告技術(shù)等,同時(shí)開發(fā)并提供大量基于互聯(lián)網(wǎng)的產(chǎn)品與服務(wù),其主要利潤(rùn)來(lái)自于關(guān)鍵詞廣告等服務(wù)。收起

查看更多

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

公眾號(hào)『嵌入式從0到1』,號(hào)主:程序員小哈,是一個(gè)軟硬件全棧開發(fā)工程師(12年工作經(jīng)驗(yàn)的老司機(jī)),電子發(fā)燒友論壇鴻蒙版塊版主,公眾號(hào)內(nèi)容專注于嵌入式學(xué)習(xí)。堅(jiān)持原創(chuàng),寫有圖、有視頻的保姆級(jí)教程文章,篇篇有干貨。做一個(gè)講清楚,說(shuō)明白,大家學(xué)得會(huì)的交流平臺(tái)。