Qt on Android 藍牙通訊開發

  版權聲明:本文爲MULTIBEANS ORG研發跟隨文章,未經MLT ORG容許不得轉載。html

 

  最近作項目,須要開發安卓應用,實現串口的收發,目測CH340G在安卓手機上很是麻煩,並且驅動都是Java版本的, 就沒選擇,博主在大二的時候學習過Java SE基本的語法,寫過一些小程序就放棄了Java的道路。最後選擇了藍牙無線透傳模塊,實現串口通訊。如今Qt跨平臺支持安卓,是在是使人欣喜。在網上找資料,用Qt on Android作藍牙驅動的幾乎沒有,也沒有相關例程,因此準備撰寫此文,獻給廣大嵌入式程序員們android

  2018/6/27更新:程序員

       增長Java版本的藍牙通訊,文章地址:https://www.cnblogs.com/sigma0/p/9234478.html小程序

1、軟硬件平臺

1.1 硬件平臺

1. 藍牙:HC-05,(淘寶上有賣),它的接口就是跟串口同樣的,咱們用到了TX,RX,GND,VCC四個引腳。跟下位機或者用CH340G TTL轉USB模塊接到PC機上。藍牙工做在串口模式能夠經過AT指令調節。具體參考藍牙配套的說明文檔,最主要的就是請將藍牙設定爲從機模式,不然安卓手機搜尋連接不上。
2.安卓手機:我這裏測試用了2檯安卓手機,一臺是小米4移動版,安卓版本6.0.1;一臺是MOTO MT887,安卓版本4.1.2。windows

1.2 軟件平臺

本項目Qt版本是5.7,系統是windows 8.1 x64app

 

2、軟件基本介紹

  由於第一次作藍牙,就作一個很是簡單的雛形,實現藍牙狀態檢測、藍牙的開關、藍牙的掃描和藍牙配對連接,而且能像串口助手同樣完成數據收發。如圖,就是本一開始作的最簡單的軟件界面,本軟件基於QWidget控件製做,固然你能夠選擇mainwinodw,更能夠本身定義類。框架

 

軟件界面socket

 

  我不用介紹每一個部位是什麼了,都會明白吧?藍牙打開後經過掃描,會將藍牙的MAC地址還有名字顯示在List中,咱們雙擊List列表中的藍牙,就會進入actived信號鏈接的槽函數,執行藍牙的配對鏈接。創建鏈接以後,就相似串口同樣能夠進行數據通訊了。另外,點擊send按鈕以後會發送一堆字符串。函數

3、 藍牙開發

3.1 項目文件準備

須要用到藍牙就須要在.pro文件中引入庫,我沒有用Qt quick,用的是純C++寫的代碼,你須要在.pro文件中加入這句話:學習

QT += bluetooth
若是沒有這句話的話,包含藍牙目錄下的頭文件,會提示找不到該文件。
 
以後就是要包含一些藍牙用到的頭文件:
 
#include <QtBluetooth/qbluetoothglobal.h>
#include <QtBluetooth/qbluetoothlocaldevice.h>
#include <qbluetoothaddress.h>
#include <qbluetoothdevicediscoveryagent.h>
#include <qbluetoothlocaldevice.h>
#include <qbluetoothsocket.h>
  一下子介紹每一個都是作什麼的。
 
請在類中聲明定義藍牙相關句柄:
QBluetoothDeviceDiscoveryAgent *discoveryAgent;
QBluetoothLocalDevice *localDevice;
QBluetoothSocket *socket;
 
  第一個discoveryAgent是用來對周圍藍牙進行搜尋,localDevice顧名思義,就是對本地設備進行操做,好比進行設備的打開,設備的關閉等等。socket就是用來進行藍牙配對連接和數據傳輸的。這裏要用到這三個。
 

3.2 藍牙開關和可見性設定

在構造函數中,請爲localDevice使用new運算符分配內存。
localDevice = new QBluetoothLocalDevice();

1) 藍牙開關

本設計在運行APP的時候,會檢測一下咱們本地設備的藍牙是否打開,若是判斷是開啓狀態,咱們能夠將打開藍牙的按鈕disable掉,將關閉藍牙的按鈕enable,因此在APP運行的時候須要進行藍牙狀態檢測。檢測方法以下:
 
進行一個這樣的檢測,對本地設備模式進行判斷。
if( localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff )  {
        ui->pushButton_openBluetooth->setEnabled(true);
        ui->pushButton_closeDevice->setEnabled(false);
}else {
        ui->pushButton_openBluetooth->setEnabled(false);
        ui->pushButton_closeDevice->setEnabled(true);
}

在構造函數中

那麼,咱們如何來對藍牙進行打開和關閉呢?我在open按鈕和close按鈕的槽函數中對藍牙進行開關操做。

open按鈕的槽函數:

void Widget::on_pushButton_openBluetooth_clicked()
{
    localDevice->powerOn();
    ui->pushButton_closeDevice->setEnabled(true);
    ui->pushButton_openBluetooth->setEnabled(false);
    ui->pushButton_scan->setEnabled(true);
}
localDevice->powerOn();方法調用打開本地的藍牙設備,而後你能夠根據本身的喜愛完成對按鈕的使能和禁止操做。
 
close按鈕的槽函數:
void Widget::on_pushButton_closeDevice_clicked()
{
    localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
    ui->pushButton_closeDevice->setEnabled(false);
    ui->pushButton_openBluetooth->setEnabled(true);
    ui->pushButton_scan->setEnabled(false);
}
close設備和咱們的open設備的方法在形式上不同,我還覺得他們兩個是對稱的,可是事實上不是,只能用這樣的方法對藍牙進行關閉。

2) 藍牙可見性

  一樣地,在藍牙使用過程當中,安卓手機提供了藍牙是否能夠被其餘藍牙搜索到這樣的功能,也就是藍牙可見,咱們也能夠用localDevice下的HostMode()方法,對這個狀態進行檢測。以下:
if( localDevice->hostMode() == QBluetoothLocalDevice::HostDiscoverable ) {
        ui->checkBox_discoverable->setChecked(true);
}else {
        ui->checkBox_discoverable->setChecked(false);
}
個人設計中,藍牙可見如界面圖用的是checkBox空間完成的,經過setChecked()方法,一開機對是否可見進行。
在翻轉checkBox的時候,會激發進入checkBox的槽函數,咱們在checkBox的槽函數中,完成對藍牙可見性的設定。代碼以下:
localDevice->setHostMode( QBluetoothLocalDevice::HostDiscoverable);
同理,不可見你也能想到對吧。
 

3.3 藍牙設備的查找

  使用藍牙設備的查找,就要用到 discoveryAgent 這個類的實例化。咱們須要在構造函數中對discoveryAgent =new QBluetoothDeviceDiscoveryAgent();分配內存。而後就可使用這個類的方法來對藍牙進行查找了。除此以外,還要進行一個信號和槽的連接。
    connect(discoveryAgent,
            SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
            this,
            SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo))
            );
  在咱們發現設備的時候,這個deviceDiscovered信號被觸發,進入到addBlueToothDevicesToList的函數中。在上面的軟件界面,咱們的最上面藍牙列表下的控件是ListIte控件,這裏作一個槽函數,將發現的設備打印到這個列表中列出來。
void Widget::addBlueToothDevicesToList( 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);
    }

}
  這裏給出這個函數,每一句話十分的好理解,這裏增長點選操做,當點擊listItem中的項目的時候,背景顏色會翻轉,雙擊這個項目就會和這個藍牙設備創建鏈接,這裏有個actived槽函數,在這個槽函數裏面就會進行藍牙的連接。下一章節寫這個如何鏈接。
 

3.4 藍牙設備的創建鏈接

  在說藍牙設備鏈接以前,不得不提一個很是重要的概念,就是藍牙的Uuid,引用一下百度的:
 
   在藍牙中,每一個服務和服務屬性都惟一地由"全球惟一標識符" (UUID)來校驗。正如它的名字所暗示的,每個這樣的標識符都要在時空上保證惟一。UUID類可表現爲短整形(16或32位)和長整形(128位)UUID。他提供了分別利用String和16位或32位數值來建立類的構造函數,提供了一個能夠比較兩個UUID(若是兩個都是128位)的方法,還有一個能夠轉換一個UUID爲一個字符串的方法。UUID實例是不可改變的(immutable),只有被UUID標示的服務能夠被發現。
在Linux下你用一個命令uuidgen -t能夠生成一個UUID值;在Windows下則執行命令uuidgen 。UUID看起來就像以下的這個形式:2d266186-01fb-47c2-8d9f-10b8ec891363。當使用生成的UUID去建立一個UUID對象,你能夠去掉連字符。
 
在咱們的項目中,用到的模式是串口模式,咱們須要創建一個存儲Uuid的機制,以下:
static const QLatin1String serviceUuid("00001101-0000-1000-8000-00805F9B34FB");
這個字符串裏面的內容就是串口模式的Uuid,若是你開發的藍牙也是要使用串口,你直接Copy過去就能夠了,若是你使用其餘模式,本身去找這個Uuid碼是多少。
 
在使用藍牙創建鏈接,須要創建藍牙socket服務。請在構造函數中增長對socket的分配內存,要注意的是構造函數中的參數須要給定模式。
 
socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
  
 
  在Qt文檔中,給了3中模式,具體如何這裏不作引伸,讀者須要請本身查詢文檔。但RfcommProtocol,屬於模擬RS232模式,我就叫串口模式了。
  在上一節中說了,當雙擊ItemList控件中的項目時候,會進入到actived槽函數和藍牙進行連接,那麼如何鏈接呢?在itemList中會打印一個藍牙的MAC地址信息,咱們會將這個Mac地址保存在QBluetoothAddress這個類的實例化中,並將這個address傳遞給socket,做爲連接依據。
void Widget::itemActivated(QListWidgetItem *item)
{
    QString text = item->text();

    int index = text.indexOf(' ');

    if (index == -1)
        return;

    QBluetoothAddress address(text.left(index));
    QString name(text.mid(index + 1));
    qDebug() << "You has choice the bluetooth address is " << address;
    qDebug() << "The device is connneting.... ";
    QMessageBox::information(this,tr("Info"),tr("The device is connecting..."));
    socket->connectToService(address, QBluetoothUuid(serviceUuid) ,QIODevice::ReadWrite);

}

  咱們經過對字符串的處理,將獲得address信息。經過socket->connectToService(....),把地址,Uuid,和藍牙模式傳遞進去,當執行完這句話的時候,安卓手機開始和你

   選擇的藍牙設備進行連接。

  一樣在socket中也提供了豐富的槽函數,好比成功創建鏈接信號,成功斷開信號,這裏在槽函數中能夠作一些例子,這裏給出例子:

 

    connect(socket,
            SIGNAL(connected()),
            this,
            SLOT(bluetoothConnectedEvent())
            );
    connect(socket,
            SIGNAL(disconnected()),
            this,
            SLOT(bluetoothDisconnectedEvent())
            );
void Widget::bluetoothConnectedEvent()
{
  // 2017/10/8 更新一下,請在這裏插入關閉藍牙查找服務,不然數據會斷。
// 具體語句是什麼我忘記了,反正使用discoveryAgent的一個什麼close,或者stop的方法
qDebug()
<< "The android device has been connected successfully!"; QMessageBox::information(this,tr("Info"),tr("successful connection!")); } void Widget::bluetoothDisconnectedEvent() { qDebug() << "The android device has been disconnected successfully!"; QMessageBox::information(this,tr("Info"),tr("successful disconnection!")); }

 

最後,還有一個斷開鏈接函數。經過斷開鏈接按鈕的槽函數實現。

void Widget::on_pushButton_disconnect_clicked()
{
    socket->disconnectFromService();

}

 

3.5 發送和接收數據

  藍牙發送和接收數據,也是經過socket進行。發送數據十分簡單:
void Widget::on_pushButton_send_clicked()
{
    QByteArray arrayData;
    QString s("Hello Windows!!!\nThis message is sended via bluetooth of android device!\n");
    arrayData = s.toUtf8();
    socket->write(arrayData);
}
這裏經過socket->write函數,完成發送。發送以後,上位機,我用的串口助手會顯示該信息。
串口助手接受到信息
 
那麼接收數據呢?
咱們在構造函數中,須要創建這樣的一個信號和槽的連接:
    connect(socket,
            SIGNAL(readyRead()),
            this,
            SLOT(readBluetoothDataEvent())
            );

 

readyRead()信號觸發,跳進readBluetoothDataEvent中。
void Widget::readBluetoothDataEvent()
{

    QByteArray line = socket->readAll();
    QString strData = line.toHex();
    comStr.append(strData);
    qDebug() <<"rec data is: "<< comStr;
    qDebug() <<"The comStr length is: " << comStr.length();
    if(comStr.length() >= 30) {

        ui->textBrowser_info->append(comStr + "\n");
        comStr.clear();
    }

}

 

我這裏是這樣處理的,固然了,你有你本身的處理方法,意思就是那麼個意思。
 

4、結束語

完成對藍牙的開發,實現了最基本的功能,這裏爲了講述用Qt開發藍牙在安卓設備上,用了最簡單最簡單的例子,給你一個思路框架方法,若是追求極高的穩定性,好須要自
己深刻研究,這裏不作討論。歡迎批評指正,我也是一個求學者,你們共同交流,共同進步。最後,貼上源碼,僅供你們參考。
 
 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
百度雲連接: http://pan.baidu.com/s/1dEB5LoX
提取碼: zykk
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
相關文章
相關標籤/搜索