Android硬件通信之 蓝牙通信

news/2024/10/21 3:48:18/

一,简介

1.1 现在的手机设备基本上都支持蓝牙模块,蓝牙与蓝牙之前可以相互通信,所以只要物联网机器上配有蓝牙模块,就可以用手机蓝牙连接机器蓝牙,从而和机器通信

1.2 蓝牙按协议常见可以分为经典蓝牙和低功耗蓝牙,下面是主要区别:

对比经典蓝牙低功耗蓝牙
协议4.0以下4.0以上
   传输速度慢,100ms

快,3ms

传输大小大,可以传大文件小,大文件需要分包 
网络拓扑点对点点对点,广播,Mesh组网
应用领域无线耳机,无线音箱鼠标,单车,智能家居,监控系统,灯光组网


 

二,经典蓝牙

2.1 开启蓝牙

获取BluetoothAdapter对象

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

2.2 判断设备是否支持蓝牙 

/*** 设备是否支持蓝牙  true为支持* @return*/
public boolean isSupportBlue(){return mBluetoothAdapter != null;
}

 2.3 判断蓝牙是否开启

/*** 蓝牙是否打开* @return*/
public boolean isBlueEnable(){return mBluetoothAdapter.isEnabled();
}

2.4 添加权限

<!-- 使用蓝牙的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 扫描蓝牙设备或者操作蓝牙设置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--模糊定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--精准定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2.5 动态请求权限

/*** 检查权限*/
private void checkPermissions() {String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};List<String> permissionDeniedList = new ArrayList<>();for (String permission : permissions) {int permissionCheck = ContextCompat.checkSelfPermission(this, permission);if (permissionCheck == PackageManager.PERMISSION_GRANTED) {onPermissionGranted(permission);} else {permissionDeniedList.add(permission);}}if (!permissionDeniedList.isEmpty()) {String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);ActivityCompat.requestPermissions(this, deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION);}
}/*** 权限回调* @param requestCode* @param permissions* @param grantResults*/
@Override
public final void onRequestPermissionsResult(int requestCode,@NonNull String[] permissions,@NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode) {case REQUEST_CODE_PERMISSION_LOCATION:if (grantResults.length > 0) {//权限成功做其它任务}break;}
}

 2.6 检查GPS是否打开

/*** 检查GPS是否打开* @return*/
private boolean checkGPSIsOpen() {LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);if (locationManager == null)return false;return locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);
}

 2.7 前往设置里面开启GPS

Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);startActivityForResult(intent, REQUEST_CODE_OPEN_GPS);

2.8 扫描蓝牙

//发现蓝牙
public void startBluetoothDiscovery() {//当前是否在扫描,如果是就取消当前的扫描,重新扫描if (mBluetoothAdapter.isDiscovering()){mBluetoothAdapter.cancelDiscovery();}mBluetoothAdapter.startDiscovery();
}

2.9 监听蓝牙扫描状态

IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙开关状态
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//蓝牙开始搜索
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//蓝牙搜索结束
filter.addAction(BluetoothDevice.ACTION_FOUND);//蓝牙发现新设备(未配对的设备)
registerReceiver(scanBlueReceiver, filter);
/*** 扫描广播接收类*/public class ScanBlueReceiver extends BroadcastReceiver {private static final String TAG = ScanBlueReceiver.class.getName();private ScanBlueCallBack callBack;public ScanBlueReceiver(ScanBlueCallBack callBack){this.callBack = callBack;}//广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();Log.d(TAG, "action:" + action);BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);switch (action){case BluetoothAdapter.ACTION_STATE_CHANGED:int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);switch (blueState) {case BluetoothAdapter.STATE_TURNING_ON:Log.e(TAG,"蓝牙正在打开中");break;case BluetoothAdapter.STATE_ON:Log.e(TAG,"蓝牙已经打开");mListener.stateOn();break;case BluetoothAdapter.STATE_TURNING_OFF:Log.e(TAG,"蓝牙正在关闭中");break;case BluetoothAdapter.STATE_OFF:Log.e(TAG,"蓝牙已经关闭");mListener.stateOff();break;}break;case BluetoothAdapter.ACTION_DISCOVERY_STARTED:Log.d(TAG, "开始扫描...");callBack.onScanStarted();break;case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:Log.d(TAG, "结束扫描...");callBack.onScanFinished();break;case BluetoothDevice.ACTION_FOUND:Log.d(TAG, "发现设备...");callBack.onScanning(device);break;}}
}

2.10 连接蓝牙

/** 连接蓝牙线程*/public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> {private static final String TAG = ConnectBlueTask.class.getName();private BluetoothDevice bluetoothDevice;private ConnectBlueCallBack callBack;public ConnectBlueTask(ConnectBlueCallBack callBack){this.callBack = callBack;}@Overrideprotected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {bluetoothDevice = bluetoothDevices[0];BluetoothSocket socket = null;try{Log.d(TAG,"开始连接socket,uuid:" + ClassicsBluetooth.UUID);socket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(ClassicsBluetooth.UUID));if (socket != null && !socket.isConnected()){socket.connect();}mOutputStream = socket.getOutputStream();mInputStream = socket.getInputStream();}catch (IOException e){Log.e(TAG,"socket连接失败");try {socket.close();} catch (IOException e1) {e1.printStackTrace();Log.e(TAG,"socket关闭失败");}}return socket;}@Overrideprotected void onPreExecute() {Log.d(TAG,"开始连接");if (callBack != null) callBack.onStartConnect();}@Overrideprotected void onPostExecute(BluetoothSocket bluetoothSocket) {if (bluetoothSocket != null && bluetoothSocket.isConnected()){Log.d(TAG,"连接成功");if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);}else {Log.d(TAG,"连接失败");if (callBack != null) callBack.onConnectFail(bluetoothDevice, "连接失败");}}
}

2.11 判断蓝牙是否连接

/*** 当前设备与指定设备是否连接*/
public boolean isBlueToothConnected() {boolean connected = (bluetoothSocket != null && bluetoothSocket.isConnected());if (bluetoothDevice == null)return connected;return connected && bluetoothSocket.getRemoteDevice().equals(bluetoothDevice);
}

2.12 读取蓝牙消息

 private class ReadThread extends Thread {@Overridepublic void run() {super.run();while (!isInterrupted()) {int size;try {byte[] buffer = new byte[512];if (mInputStream == null) return;size = mInputStream.read(buffer);if (size > 0) {String mReception=new String(buffer, 0, size);String msg = mReception.toString().trim();Log.e(TAG, "接收短消息:" + msg);}} catch (IOException e) {e.printStackTrace();return;}}}}

 2.13 发送蓝牙指令

 private class WriteRunnable implements Runnable {@Overridepublic void run() {try {String cmd="KZMT;";Log.e(TAG, "发送短消息:" + cmd);mOutputStream.write(cmd.getBytes());mOutputStream.flush();} catch (IOException e) {}}}

2.14 断开连接

/*** 关闭蓝牙Socket连接*/
public void closeBluetoothStream() {try {    if (mOutputStream != null) {mOutputStream.close();mOutputStream = null;}if (mInputStream != null) {mInputStream.close();mInputStream = null;}if (bluetoothSocket != null) {if (bluetoothSocket.isConnected()) {bluetoothSocket.close();}bluetoothSocket = null;}} catch (Exception e) {e.printStackTrace();}
}

三,低功耗蓝牙

3.1 低功耗蓝牙扫描之前的步骤都一样,开启,请求权限等,从扫描开始有变化,所以扫描之前步骤可以参考经典蓝牙,下面是扫描的操作:

    private BluetoothAdapter mBluetoothAdapter;private boolean isScanning;//是否正在搜索private Handler mHandler;//15秒搜索时间private static final long SCAN_PERIOD = 15000;private void scanLeDevice(final boolean enable) {if (enable) {//true//15秒后停止搜索mHandler.postDelayed(new Runnable() {@Overridepublic void run() {isScanning = false;mBluetoothAdapter.stopLeScan(mLeScanCallback);}}, SCAN_PERIOD);isScanning = true;mBluetoothAdapter.startLeScan(mLeScanCallback); //开始搜索} else {//falseisScanning = false;mBluetoothAdapter.stopLeScan(mLeScanCallback);//停止搜索}} private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {//这里是个子线程,下面把它转换成主线程处理runOnUiThread(new Runnable() {@Overridepublic void run() {//在这里可以把搜索到的设备保存起来//device.getName();获取蓝牙设备名字//device.getAddress();获取蓝牙设备mac地址//这里的rssi即信号强度,即手机与设备之间的信号强度。}});}};

3.2 停止扫描

mBluetoothAdapter.stopLeScan(mLeScanCallback);//停止搜索

3.3 连接蓝牙

//这个方法需要三个参数:一个Context对象,自动连接(boolean值,表示只要BLE设备可用是否自动连接它),和BluetoothGattCallback调用。
BluetoothGatt mBluetoothGatt = device.connectGatt(this, false, mBluetoothGattCallback);BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {@Overridepublic void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {super.onPhyUpdate(gatt, txPhy, rxPhy, status);}@Overridepublic void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {super.onPhyRead(gatt, txPhy, rxPhy, status);}//当连接状态发生改变@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {super.onConnectionStateChange(gatt, status, newState);}//发现新服务,即调用了mBluetoothGatt.discoverServices()后,返回的数据@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {super.onServicesDiscovered(gatt, status);}//调用mBluetoothGatt.readCharacteristic(characteristic)读取数据回调,在这里面接收数据@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicRead(gatt, characteristic, status);}//发送数据后的回调@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicWrite(gatt, characteristic, status);}@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {super.onCharacteristicChanged(gatt, characteristic);}@Overridepublic void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {//descriptor读super.onDescriptorRead(gatt, descriptor, status);}@Overridepublic void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {//descriptor写super.onDescriptorWrite(gatt, descriptor, status);}@Overridepublic void onReliableWriteCompleted(BluetoothGatt gatt, int status) {super.onReliableWriteCompleted(gatt, status);}//调用mBluetoothGatt.readRemoteRssi()时的回调,rssi即信号强度@Overridepublic void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {//读Rssisuper.onReadRemoteRssi(gatt, rssi, status);}@Overridepublic void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {super.onMtuChanged(gatt, mtu, status);}};

3.4 断开连接

mBluetoothGatt.disconnect(); //主动断开连接

3.5 写入数据,通过mBluetoothGatt.writeCharacteristic(characteristic)

写入的数据长度是有限制的,如果要改变这个限制,可以通过MTU来改变

/*** 向蓝牙发送数据*/
public void dataSend(){//byte[] send={(byte) 0xaa,0x01,0x01,(byte)0x81,(byte) 0xff};byte[] send = new byte[20];send = hexStringToBytes(et_send.getText().toString());byte[] sendData=new byte[send.length+2];sendData[0]=(byte) 0xaa;sendData[sendData.length-1]=(byte) 0xff;for(int i=1;i<sendData.length-1;i++){sendData[i]=send[i-1];}mCharacteristic.setValue(sendData);boolean status = mBluetoothGatt.writeCharacteristic(mCharacteristic);
}

3.6 读取数据,通过mBluetoothGatt.readCharacteristic(characteristic),在BluetoothGattCallback 回调方法onCharacteristicRead中获取到数据。

//读取数据时调用这个方法,数据会在回调接口中(BluetoothGattCallback )获取到
mBluetoothGatt.readCharacteristic(characteristic)BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {     //调用mBluetoothGatt.readCharacteristic(characteristic)读取数据回调,在这里面接收数据@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicRead(gatt, characteristic, status);//这里面就是数据characteristic.getValue();}
}

3.7 总结

第一步:我们要判断手机是否支持BLE,并且获得各种权限,才能让我们之后的程序能正常运行。 
然后,我们去搜索BLE设备,得到它的MAC地址。 
第二步:我们通过这个MAC地址去连接,连接成功后,去遍历得到Characteristic的uuid。 
在我们需要发送数据的时候,通过这个uuid找到Characteristic,去设置其值,最后通过writeCharacteristic(characteristic)方法发送数据。 
如果我们想知道手机与BLE设备的距离,则可以通过readRemoteRssi()去得到rssi值,通过这个信号强度,就可以换算得到距离。 
第三步:连接上后,我们就可以用BluetoothGatt的各种方法进行数据的读取等操作

3.8 相关api

1、BluetoothManager

通过BluetoothManager来获取BluetoothAdapter。 

2、BluetoothAdapter

代表了移动设备的本地的蓝牙适配器, 通过该蓝牙适配器可以对蓝牙进行基本操作,一个Android系统只有一个BluetoothAdapter,通过BluetoothManager获取。 

3、BluetoothDevice

扫描后发现可连接的设备,获取已经连接的设备,通过它可以获取到BluetoothGatt。

4、BluetoothGatt

继承BluetoothProfile,通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback,可以看成蓝牙设备从连接到断开的生命周期。

5、BluetoothGattService

服务,Characteristic的集合。

6、BluetoothGattCharacteristic

相当于一个数据类型,可以看成一个特征或能力,它包括一个value和0~n个value的描述(BluetoothGattDescriptor)。

7、BluetoothGattDescriptor

描述符,对Characteristic的描述,包括范围、计量单位等。

8、BluetoothProfile

一个通用的规范,按照这个规范来收发数据。 

9、BluetoothGattCallback

已经连接上设备,对设备的某些操作后返回的结果。

10、总结:当我们扫描后发现多个设备BluetoothDevice,每个设备下会有很多服务BluetoothGattService,这些服务通过service_uuid(唯一标识符)来区分,每个服务下又会有很多特征BluetoothGattCharacteristic,这些特征通过uuid来区分的,它是手机与BLE终端设备交换数据的关键。而BluetoothGatt可以看成手机与BLE终端设备建立通信的一个管道,只有有了这个管道,才有了通信的前提


http://www.ppmy.cn/news/461306.html

相关文章

电赛小车常用硬件解析(蓝牙遥控,循迹)

智能小车硬件解析 &#xff08;蓝牙遥控、循迹&#xff09;智能小车硬件解析 智能小车硬件解析前言一、单片机1.什么是单片机2.STM32F103C8T63.小车项目总览4.器材清单 二、电机1.直流减速电机&#xff08;1&#xff09;驱动方法&#xff08;2&#xff09;电机参数 2.带编码器的…

BlueTooth: 蓝牙介绍

蓝牙简介&#xff1a; “蓝牙”是一种大容量近距离无线数字通信技术标准&#xff0c;其目标是实现最高数据传输速率1Mbps、最大传输距离为10厘米&#xff5e;10米&#xff0c;通过增加发射功率可达到100米。 蓝牙技术是爱立信、IBM等5家公司在1998年联合推出的一项无线网络技术…

蓝牙核心技术了解(蓝牙协议、架构、硬件和软件笔记)

https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf 声明&#xff1a;这篇文章是楼主beautifulzzzz学习网上关于蓝牙的相关知识的笔记&#xff0c;其中比较多的受益于xubin341719的蓝牙系列文章&#xff0c;同时还有其他网上作者的资料。由于有些文章…

1、蓝牙核心技术了解(蓝牙协议、架构、硬件和软件笔记)

原文地址&#xff1a;http://www.cnblogs.com/zjutlitao/p/4742428.html 声明&#xff1a;这篇文章是楼主beautifulzzzz学习网上关于蓝牙的相关知识的笔记&#xff0c;其中比较多的受益于xubin341719的蓝牙系列文章&#xff0c;同时还有其他网上作者的资料。由于有些文章只做参…

蓝牙核心技术介绍(蓝牙协议、架构、硬件和软件笔记)

原文地址&#xff1a;http://www.cnblogs.com/zjutlitao/p/4742428.html 声明&#xff1a;这篇文章是楼主beautifulzzzz学习网上关于蓝牙的相关知识的笔记&#xff0c;其中比较多的受益于xubin341719的蓝牙系列文章&#xff0c;同时还有其他网上作者的资料。由于有些文章只做参…

搞定蓝牙——第二篇(蓝牙架构)

哪吒跑过去掰扯着她师傅手里的法宝&#xff0c;左看右看&#xff0c;嘴里嘟囔着&#xff0c;这叫蓝牙的法宝怎么这么厉害呢&#xff0c;怎么都看不明白。太乙真人笑眯眯的对她说&#xff0c;来吧&#xff0c;我带你走进蓝牙的时间&#xff0c;让你一窥里面的奥秘。。。 蓝牙控…

[蓝牙] 1、蓝牙核心技术了解(蓝牙协议、架构、硬件和软件笔记)

声明:这篇文章是楼主beautifulzzzz学习网上关于蓝牙的相关知识的笔记,其中比较多的受益于xubin341719的蓝牙系列文章,同时还有其他网上作者的资料。由于有些文章只做参考或统计不足,如涉及版权请在下面留言~。同时我也在博客分类中新建一个蓝牙通信分类,用来研究分享蓝牙相…

蓝牙硬件简介

蓝牙硬件模块由蓝牙协议栈的无线收发器&#xff08;RF&#xff09;、基带控制器&#xff08;BB&#xff09;和链路管理层&#xff08;LMP&#xff09;组成。大多数生产厂家都是利用片上系统技术SOC&#xff08;System-On-Chip&#xff09;将这三层功能模块集嵌在同一块芯片上。…