版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载。

  最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本的, 就没选择,博主在大二的时候学习过Java SE基本的语法,写过一些小程序就放弃了Java的道路。最后选择了蓝牙无线透传模块,实现串口通信。现在Qt跨平台支持安卓,是在是令人欣喜。在网上找资料,用Qt on Android做蓝牙驱动的几乎没有,也没有相关例程,所以准备撰写此文,献给广大嵌入式程序员们

  2018/6/27更新:

增加Java版本的蓝牙通信,文章地址:https://www.cnblogs.com/sigma0/p/9234478.html

一、软硬件平台

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。

1.2 软件平台

本项目Qt版本是5.7,系统是windows 8.1 x64

二、软件基本介绍

  因为第一次做蓝牙,就做一个非常简单的雏形,实现蓝牙状态检测、蓝牙的开关、蓝牙的扫描和蓝牙配对链接,并且能像串口助手一样完成数据收发。如图,就是本一开始做的最简单的软件界面,本软件基于QWidget控件制作,当然你可以选择mainwinodw,更可以自己定义类。

软件界面

  我不用介绍每个部位是什么了,都会明白吧?蓝牙打开后通过扫描,会将蓝牙的MAC地址还有名字显示在List中,我们双击List列表中的蓝牙,就会进入actived信号连接的槽函数,执行蓝牙的配对连接。建立连接之后,就类似串口一样可以进行数据通信了。另外,点击send按钮之后会发送一堆字符串。

三、 蓝牙开发

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 == -)
return; QBluetoothAddress address(text.left(index));
QString name(text.mid(index + ));
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() >= ) { ui->textBrowser_info->append(comStr + "\n");
comStr.clear();
} }

我这里是这样处理的,当然了,你有你自己的处理方法,意思就是那么个意思。

 

四、结束语

完成对蓝牙的开发,实现了最基本的功能,这里为了讲述用Qt开发蓝牙在安卓设备上,用了最简单最简单的例子,给你一个思路框架方法,如果追求极高的稳定性,好需要自
己深入研究,这里不做讨论。欢迎批评指正,我也是一个求学者,大家共同交流,共同进步。最后,贴上源码,仅供大家参考。
 
 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
提取码: zykk
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 

Qt on Android 蓝牙通信开发的更多相关文章

  1. Android 串口蓝牙通信开发Java版本

    Android串口BLE蓝牙通信Java版 0. 导语 Qt on Android 蓝牙通信开发 我们都知道,在物联网中,BLE蓝牙是通信设备的关键设备.在传统的物联网应用中,无线WIFI.蓝牙和Zi ...

  2. Android蓝牙BLE开发,扫描、连接、发送和读取信息;

    1.BLE开发权限 Android蓝牙BLE开发须打开蓝牙权限和6.0位置权限: <uses-permission android:name="android.permission.B ...

  3. Android蓝牙——HID开发

    代码地址如下:http://www.demodashi.com/demo/13891.html 原文地址: https://blog.csdn.net/VNanyesheshou/article/de ...

  4. Qt on Android 蓝牙开发

    版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...

  5. Android蓝牙通信总结

    这篇文章要达到的目标: 1.介绍在Android系统上实现蓝牙通信的过程中涉及到的概念. 2.在android系统上实现蓝牙通信的步骤. 3.在代码实现上的考虑. 4.例子代码实现(手持设备和蓝牙串口 ...

  6. Android蓝牙通信具体解释

    蓝牙通信的大概过程例如以下: 1.首先开启蓝牙 2,搜索可用设备 3,创建蓝牙socket.获取输入输出流 4,读取和写入数据 5.断开连接关闭蓝牙 还要发送配对码发送进行推断! 以下是全部的源码:不 ...

  7. android蓝牙通讯开发(详细)

    新建一个工程之后,我们可以先看到界面左边的项目栏,我们可以看到,除了app目录以外,大多数的文件和目录都是自动生成的,我们也不需要对他们进行修改,而app目录之下的文件才是我们工作的重点.下面,我先对 ...

  8. Android蓝牙通信

    Android为蓝牙设备之间的通信封装好了一些调用接口,使得实现Android的蓝牙通信功能并不困难.可通过UUID使两个设备直接建立连接. 具体步骤: 1. 获取BluetoothAdapter实例 ...

  9. Android蓝牙通信功能开发

    1. 概述 Bluetooth 是几乎现在每部手机标准配备的功能,多用于耳机 mic 等设备与手机的连接,除此之外,还可以多部手机之间建立 bluetooth 通信,本文就通过 SDK 中带的一个聊天 ...

随机推荐

  1. Python 基于固定 IP 来命名 ARM 虚拟机的实现

    问题描述 希望通过 Python 批量创建 ARM 虚拟机,并且在虚拟机命名时加入固定 IP 信息,方便管理维护. 问题分析 在创建 ARM 虚拟机之前,先创建固定 IP,然后获取固定 IP 地址,创 ...

  2. TELNET_COMMAND

    TELENT COMMAND DEFINE:Telnet is a command control your cmd windows of remote computer. step: 1.Open ...

  3. meat标签使用

    meta是html语言head区的一个辅助性标签.几乎所有的网页里,我们可以看到类似下面这段的html代码: <head> <meta http-equiv="conten ...

  4. Jmeter入门14 后置处理器JSON Extractor 提取json的多个值

    json串 []表示对象组成的数组,{}表示对象. 对象里包含多个 "属性":属性值.属性值可以是值,或数组,或对象. JSON Extractor使用json path表达式匹配 ...

  5. hdu 6243,6247

    题意:n只狗,n个笼子,每个笼子只能有一只,求不在自己笼子的狗的数量的期望. 分析:概率是相等的,可以直接用方案数代替,k 不在自己的笼子的方案数是 n!- (n-1)!,这样的k有n个,总的方案数n ...

  6. 三、详述 IntelliJ IDEA 的使用界面

    是否还记得在博文“IntelliJ IDEA 安装目录的核心文件讲解”中,这张充满神秘色彩的图片呢?进入她,让咱们一起感受她的魅力吧! 如上图所示,打开 IntelliJ IDEA 后,首先迎接咱们的 ...

  7. 使用Vue做评论+localStorage存储(js模块化)

    未分模块化 html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> &l ...

  8. AngularJS 二 指令介绍

    初始化AngularJS框架 ng-app指令: 在NG-程序指令是AngularJS应用程序的起点.它自动初始化AngularJS框架.AngularJS框架将在加载整个文档之后首先检查HTML文档 ...

  9. JVM垃圾回收补充知识点

    1. 分代 虚拟机中的共划分为三个代: 年轻代(Young Gen):eden和survivor-8:1:1 年老代(Old Gen):存储大对象,由survivor晋升 永久代(perm Gen): ...

  10. Aspose.cell C# 操作excel(通过批注信息给单元格赋值、批注信息获取公式得出结果并转PNG)

    if (fileName == "") return ""; var CurrentRow = 0; Workbook work = new Workbook( ...