蓝牙开发 基础知识
零、基础知识
0.1、Android 应用可通过 Bluetooth API 执行以下操作
- 扫描其他蓝牙设备
- 查询本地蓝牙适配器的配对蓝牙设备
- 建立 RFCOMM 通道
- 通过服务发现连接到其他设备
- 与其他设备进行双向数据传输
- 管理多个连接
0.2、蓝牙进行通信的四大必需任务
- 设置蓝牙
- 查找局部区域内的配对设备或可用设备
- 连接设备
- 在设备之间传输数据
0.3、动作
请求连接、接受连接和传输数据
蓝牙协议是适用于设备间蓝牙通信的无线接口规范。
如果手机要与无线耳机进行连接,则两台设备都必须支持免提蓝牙协议。
0.4、协议
- HFP协议:Android 提供 BluetoothHeadset 类,该类是用于控制蓝牙耳机服务的代理。其中包括蓝牙耳机和免提 (v1.5) 的协议。BluetoothHeadset 类包含对 AT 命令的支持。
- A2DP协议:定义如何通过蓝牙连接和流式传输,将高质量音频从一个设备传输至另一个设备。Android 提供 BluetoothA2dp 类,该类是用于控制蓝牙 A2DP 服务的代理。
- 蓝牙健康设备 (HDP)协议:该协议允许您创建应用,从而与支持蓝牙功能的健康设备(例如心率监测仪、血糖仪、温度计、台秤等)进行通信。
0.5、名词
- RFCOMM 通道
- AT 命令
- 耳机协议
- BluetoothHeadset类
- BluetoothSocket类
- SDP lookup of uuid
- SDP record
供应商特定的 AT 命令
从 Android 3.0(API 级别 11)开始,应用可注册接收耳机发送的预定义供应商特定 AT 命令(例如 Plantronics +XEVENT 命令)的系统广播。例如,应用可接收指示所连接设备电池电量的广播,并根据需要通知用户或采取其他操作。为 ACTION_VENDOR_SPECIFIC_HEADSET_EVENT Intent 创建广播接收器,以处理耳机的供应商特定 AT 命令。
一、使用蓝牙
1.1 设置蓝牙
启用蓝牙:
获取 BluetoothAdapter。
所有蓝牙 Activity 都需要 BluetoothAdapter。如要获取 BluetoothAdapter,请调用静态的 getDefaultAdapter() 方法。此方法会返回一个 BluetoothAdapter 对象,表示设备自身的蓝牙适配器(蓝牙无线装置)。整个系统只有一个蓝牙适配器,并且您的应用可使用此对象与之进行交互。如果 getDefaultAdapter() 返回 null,则表示设备不支持蓝牙。
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {// Device doesn't support Bluetooth
} else {if (!bluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}
}
如果成功启用蓝牙,您的 Activity 会在 onActivityResult() 回调中收到 RESULT_OK 结果代码。如果由于某个错误(或用户响应“No”)未成功启用蓝牙,则结果代码为 RESULT_CANCELED。
1.2 查找设备
1.2.1 设备发现
如要开始发现设备,只需调用 startDiscovery()。该进程为异步操作,并且会返回一个布尔值,指示发现进程是否已成功启动。发现进程通常包含约 12 秒钟的查询扫描,随后会对发现的每台设备进行页面扫描,以检索其蓝牙名称。
@Override
protected void onCreate(Bundle savedInstanceState) {...// Register for broadcasts when a device is discovered.IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(receiver, filter);
}// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_FOUND.equals(action)) {// Discovery has found a device. Get the BluetoothDevice// object and its info from the Intent.BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);String deviceName = device.getName();String deviceHardwareAddress = device.getAddress(); // MAC address}}
};@Override
protected void onDestroy() {super.onDestroy();...// Don't forget to unregister the ACTION_FOUND receiver.unregisterReceiver(receiver);
}
1.2.2 查询配对设备的列表
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();if (pairedDevices.size() > 0) {// There are paired devices. Get the name and address of each paired device.for (BluetoothDevice device : pairedDevices) {String deviceName = device.getName();String deviceHardwareAddress = device.getAddress(); // MAC address}
}
1.2.3 启用可检测性
Intent discoverableIntent =new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); // 可检测性开启300秒
startActivity(discoverableIntent);
注意:如果尚未在设备上启用蓝牙,则启用设备可检测性会自动启用蓝牙。
1.2.4 已配对与已连接的区别
已配对是指两台设备知晓彼此的存在,具有可用于身份验证的共享链路密钥,并且能够与彼此建立加密连接。
已连接是指设备当前共享一个 RFCOMM 通道,并且能够向彼此传输数据。当前的 Android Bluetooth API 要求规定,只有先对设备进行配对,然后才能建立 RFCOMM 连接。在使用 Bluetooth API 发起加密连接时,系统会自动执行配对。
二、连接设备
2.1. 连接技术
2.1.1 作为服务器连接
private class AcceptThread extends Thread {private final BluetoothServerSocket mmServerSocket;public AcceptThread() {// Use a temporary object that is later assigned to mmServerSocket// because mmServerSocket is final.BluetoothServerSocket tmp = null;try {// MY_UUID is the app's UUID string, also used by the client code.tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {Log.e(TAG, "Socket's listen() method failed", e);}mmServerSocket = tmp;}public void run() {BluetoothSocket socket = null;// Keep listening until exception occurs or a socket is returned.while (true) {try {socket = mmServerSocket.accept();} catch (IOException e) {Log.e(TAG, "Socket's accept() method failed", e);break;}if (socket != null) {// A connection was accepted. Perform work associated with// the connection in a separate thread.manageMyConnectedSocket(socket);mmServerSocket.close();break;}}}// Closes the connect socket and causes the thread to finish.public void cancel() {try {mmServerSocket.close();} catch (IOException e) {Log.e(TAG, "Could not close the connect socket", e);}}
}
2.1.2 作为客户端连接
private class ConnectThread extends Thread {private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device) {// Use a temporary object that is later assigned to mmSocket// because mmSocket is final.BluetoothSocket tmp = null;mmDevice = device;try {// Get a BluetoothSocket to connect with the given BluetoothDevice.// MY_UUID is the app's UUID string, also used in the server code.tmp = device.createRfcommSocketToServiceRecord(MY_UUID);} catch (IOException e) {Log.e(TAG, "Socket's create() method failed", e);}mmSocket = tmp;}public void run() {// Cancel discovery because it otherwise slows down the connection.bluetoothAdapter.cancelDiscovery();try {// Connect to the remote device through the socket. This call blocks// until it succeeds or throws an exception.mmSocket.connect();} catch (IOException connectException) {// Unable to connect; close the socket and return.try {mmSocket.close();} catch (IOException closeException) {Log.e(TAG, "Could not close the client socket", closeException);}return;}// The connection attempt succeeded. Perform work associated with// the connection in a separate thread.manageMyConnectedSocket(mmSocket);}// Closes the client socket and causes the thread to finish.public void cancel() {try {mmSocket.close();} catch (IOException e) {Log.e(TAG, "Could not close the client socket", e);}}
}
相关文章:
蓝牙开发 基础知识
零、基础知识 0.1、Android 应用可通过 Bluetooth API 执行以下操作 扫描其他蓝牙设备查询本地蓝牙适配器的配对蓝牙设备建立 RFCOMM 通道通过服务发现连接到其他设备与其他设备进行双向数据传输管理多个连接 0.2、蓝牙进行通信的四大必需任务 设置蓝牙查找局部区域内的配对…...

QNX 7.0.0开发总结
1 QNX编译 1.1 基本概念 QNX可以直接使用Linux Makefile编译库和二进制,在Makefile文件中指定CCaarch64-unknown-nto-qnx7.0.0-g,或者CCx86_64-pc-nto-qnx7.0.0-g,保存退出后,运行source /qnx_sdk_path/qnxsdp-env.sh,…...

Golang使用讯飞星火AI接口
一、API申请 https://www.bilibili.com/video/BV1Yw411m7Rs/?spm_id_from333.337.search-card.all.click&vd_source707ec8983cc32e6e065d5496a7f79ee6 注册申请,需要在此页面获取appid、apisecret、apikey https://www.xfyun.cn/ https://console.xfyun.cn/ser…...
矫正儿童发音好帮手
《言语构音语音训练手册——下颌、唇部、舌部构音运动障碍》教辅书 儿童言语构音语音问题越来越受到家长的关注,大多数家长受到儿童说话晚、口齿不清、发音错误等问题的困扰,国外报道2岁儿童言语构音语音障碍达到17%,3岁达4%~7.5%࿰…...

wordpress主题导航主题v4.16.2哈哈版
1.下载授权接口源码onenav-auth-api-v2.zip ,在宝塔新建一个网站,域名为 auth.iotheme.cn,设置wordpress伪静态,申请ssl证书。将上面源码解压后上传到此网站根目录。 2. 在宝塔根目录etc下 hosts 中添加 127.0.0.1 auth.iotheme.…...
内存分布图
1.基本数据类型和常量存放在常量池中。 2.类的成员存放在堆中,如果成员是其他类对象也存放在堆中 3.数组和数组的内容放在堆中 4.类对象存放在栈中。 5.单独的对象存放在栈中。 6.引用数据类型存放在堆或栈中。 Java中对象到底存在堆中还是栈中_java对象在堆还…...
如何发布自己的NPM插件包?
安装 Node.js : 如果没有安装的,Nodejs下载安装:http://nodejs.cn/download/ 首先确保你已经安装了 Node.js 和 npm。你可以通过运行以下命令来检查是否已经安装: node -v npm -v初始化项目: 创建一个新的项目文件夹…...
计算广告读书杂记-待整理
不知不觉已经在字节干了两年多广告研发,也跳槽去了一家广告公司继续深耕,借着这个劲,重新读一遍《计算广告》这本书,并将一些重点概念进行记录。...

No module named _sqlite3解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

防飞单,赢市场:售楼处客流统计管理新篇章
在竞争激烈的房地产市场中,售楼处作为楼盘销售的重要窗口,其管理效率和服务质量直接关系到楼盘的销售业绩和品牌形象。然而,传统的客户人数统计方式往往存在诸多不足,如数据不准确、统计效率低下等,这些问题给售楼处的…...

LeetCode:419. 甲板上的战舰(遍历 Java)
目录 419. 甲板上的战舰 题目描述: 实现代码与解析: 遍历 原理思路: 419. 甲板上的战舰 题目描述: 给你一个大小为 m x n 的矩阵 board 表示甲板,其中,每个单元格可以是一艘战舰 X 或者是一个空位 . &…...

【python】OpenCV—Blob Detection(11)
学习来自OpenCV基础(10)使用OpenCV进行Blob检测 文章目录 1、cv2.SimpleBlobDetector_create 中文文档2、默认 parameters3、配置 parameters附录——cv2.drawKeypoints 1、cv2.SimpleBlobDetector_create 中文文档 cv2.SimpleBlobDetector_create 是 O…...
【C++】 基础复习 | 数据类型,输入,输出流 scanf printf
文章目录 1 基本数据类型1.1 基本数据类型1.2 构造类型1.3 指针类型(Pointers) 2 基础输入输出2.1 通过输入输出操作符>> <<2.2 通过scanf和printf输入和输出2.2.1 输出printf 函数2.2.2 输出scanf 函数2.2.3 注意事项 1 基本数据类型 了解…...

linux pxe和无人值守
一 PXE和无人值守 pxe c/s模式 允许客户端通过网络从远程服务器(服务端)下载引导镜像 加载安装文件 实现自动化安装操作系统 无人值守 就是安装选项不需要认为干预 可以自动化实现 pxe的优点 1 规模化 同时装配多台服务器 20多 30台 2 自动化 …...

Questflow借助MongoDB Atlas以AI重新定义未来工作方式
MongoDB客户案例导读 Questflow借助MongoDB Atlas赋能AI员工,助力中小型初创企业自动化工作流程,简化数据分析,提升客户体验,推动AI与员工的协作,重新定义未来工作方式。 协作式AI自动化平台 无需编码即可拥有自己的…...
数值计算精度问题(浮点型和双整型累加精度测试)
这篇博客介绍双整型和浮点数累加精度问题,运动控制轨迹规划公式有大量对时间轴的周期累加过程,如果我们采用浮点数进行累加,势必会影响计算精度。速度的不同 进一步影响位置积分运算。轨迹规划相关问题请参考下面系列文章,这里不再赘述: 1、博途PLC 1200/1500PLC S型速度曲…...
算法训练营day56
题目1:300. 最长递增子序列 - 力扣(LeetCode) class Solution { public:int lengthOfLIS(vector<int>& nums) {// dp数组含义是第i个数的严格递增子序列的长度// 内层的递推公式就是 取 0 到 i - 1之间最大的dp数组 然后 1vector…...

基于STM32的智能水产养殖系统(二)
TPS5433IDR TPS5433IDR 是一款由德州仪器 (Texas Instruments) 生产的高效降压转换器(Buck Converter)。它能够将较高的输入电压转换为较低的输出电压,适用于各种电源管理应用。 主要特性 输入电压范围: 5.5V 至 36V输出电压范围: 0.9V 至 …...

[工具探索]富士mini90拍立得使用指南
文章目录 1. 基本功能介绍1.1 相机外观1.2 电池与胶片 2. 设置相机2.1 装入电池2.2 装入胶片 3. 拍摄模式3.1 标准模式3.2 儿童模式3.3 远景模式3.4 双重曝光模式3.5 Bulb(B)模式3.6 **派对模式**3.7 微距模式3.8 **亮度模式**3.9 **定时拍摄模式**3.10 …...

VMware导入小白分享的MacOS版本之后,无法开机的解决方案
前言 这段时间陆续有小伙伴找到小白,说:导入小白分享的MacOS版本之后,出现无法开机的问题。 遇到这个问题,并不是说明分享版本有问题,因为大部分小伙伴导入之后都没有出现类似的问题,都是导入之后开机&…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...