Android蓝牙开发浅析

2023-10-31

由于近期正在开发一个通过蓝牙进行数据传递的模块,在参考了有关资料,并详细阅读了Android的官方文档后,总结了Android中蓝牙模块的使用。

【更新】之前承诺的蓝牙通讯模块的源码已经放出,详情请点击一下链接

http://blog.csdn.net/gd920129/article/details/7552110


1. 使用蓝牙的响应权限

[html]  view plain copy
  1. <uses-permission android:name="android.permission.BLUETOOTH" />  
  2. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />  


2. 配置本机蓝牙模块

在这里首先要了解对蓝牙操作一个核心类BluetoothAdapter

[java]  view plain copy
  1. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();  
  2. //直接打开系统的蓝牙设置面板  
  3. Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
  4. startActivityForResult(intent, 0x1);  
  5. //直接打开蓝牙  
  6. adapter.enable();  
  7. //关闭蓝牙  
  8. adapter.disable();  
  9. //打开本机的蓝牙发现功能(默认打开120秒,可以将时间最多延长至300秒)  
  10. Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
  11. discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//设置持续时间(最多300秒)  


3.搜索蓝牙设备

使用BluetoothAdapter的startDiscovery()方法来搜索蓝牙设备

startDiscovery()方法是一个异步方法,调用后会立即返回。该方法会进行对其他蓝牙设备的搜索,该过程会持续12秒。该方法调用后,搜索过程实际上是在一个System Service中进行的,所以可以调用cancelDiscovery()方法来停止搜索(该方法可以在未执行discovery请求时调用)。

请求Discovery后,系统开始搜索蓝牙设备,在这个过程中,系统会发送以下三个广播:

ACTION_DISCOVERY_START:开始搜索

ACTION_DISCOVERY_FINISHED:搜索结束

ACTION_FOUND:找到设备,这个Intent中包含两个extra fields:EXTRA_DEVICE和EXTRA_CLASS,分别包含BluetooDevice和BluetoothClass。

我们可以自己注册相应的BroadcastReceiver来接收响应的广播,以便实现某些功能

[java]  view plain copy
  1. // 创建一个接收ACTION_FOUND广播的BroadcastReceiver  
  2. private final BroadcastReceiver mReceiver = new BroadcastReceiver() {  
  3.     public void onReceive(Context context, Intent intent) {  
  4.         String action = intent.getAction();  
  5.         // 发现设备  
  6.         if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
  7.             // 从Intent中获取设备对象  
  8.             BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
  9.             // 将设备名称和地址放入array adapter,以便在ListView中显示  
  10.             mArrayAdapter.add(device.getName() + "\n" + device.getAddress());  
  11.         }  
  12.     }  
  13. };  
  14. // 注册BroadcastReceiver  
  15. IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);  
  16. registerReceiver(mReceiver, filter); // 不要忘了之后解除绑定  



4. 蓝牙Socket通信

如果打算建议两个蓝牙设备之间的连接,则必须实现服务器端与客户端的机制。当两个设备在同一个RFCOMM channel下分别拥有一个连接的BluetoothSocket,这两个设备才可以说是建立了连接。

服务器设备与客户端设备获取BluetoothSocket的途径是不同的。服务器设备是通过accepted一个incoming connection来获取的,而客户端设备则是通过打开一个到服务器的RFCOMM channel来获取的。


服务器端的实现

通过调用BluetoothAdapter的listenUsingRfcommWithServiceRecord(String, UUID)方法来获取BluetoothServerSocket(UUID用于客户端与服务器端之间的配对)

调用BluetoothServerSocket的accept()方法监听连接请求,如果收到请求,则返回一个BluetoothSocket实例(此方法为block方法,应置于新线程中)

如果不想在accept其他的连接,则调用BluetoothServerSocket的close()方法释放资源(调用该方法后,之前获得的BluetoothSocket实例并没有close。但由于RFCOMM一个时刻只允许在一条channel中有一个连接,则一般在accept一个连接后,便close掉BluetoothServerSocket

[java]  view plain copy
  1. private class AcceptThread extends Thread {  
  2.     private final BluetoothServerSocket mmServerSocket;  
  3.   
  4.     public AcceptThread() {  
  5.         // Use a temporary object that is later assigned to mmServerSocket,  
  6.         // because mmServerSocket is final  
  7.         BluetoothServerSocket tmp = null;  
  8.         try {  
  9.             // MY_UUID is the app's UUID string, also used by the client code  
  10.             tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);  
  11.         } catch (IOException e) { }  
  12.         mmServerSocket = tmp;  
  13.     }  
  14.   
  15.     public void run() {  
  16.         BluetoothSocket socket = null;  
  17.         // Keep listening until exception occurs or a socket is returned  
  18.         while (true) {  
  19.             try {  
  20.                 socket = mmServerSocket.accept();  
  21.             } catch (IOException e) {  
  22.                 break;  
  23.             }  
  24.             // If a connection was accepted  
  25.             if (socket != null) {  
  26.                 // Do work to manage the connection (in a separate thread)  
  27.                 manageConnectedSocket(socket);  
  28.                 mmServerSocket.close();  
  29.                 break;  
  30.             }  
  31.         }  
  32.     }  
  33.   
  34.     /** Will cancel the listening socket, and cause the thread to finish */  
  35.     public void cancel() {  
  36.         try {  
  37.             mmServerSocket.close();  
  38.         } catch (IOException e) { }  
  39.     }  
  40. }  



客户端的实现

通过搜索得到服务器端的BluetoothService

调用BluetoothService的listenUsingRfcommWithServiceRecord(String, UUID)方法获取BluetoothSocket(该UUID应该同于服务器端的UUID)

调用BluetoothSocket的connect()方法(该方法为block方法),如果UUID同服务器端的UUID匹配,并且连接被服务器端accept,则connect()方法返回

注意:在调用connect()方法之前,应当确定当前没有搜索设备,否则连接会变得非常慢并且容易失败

[java]  view plain copy
  1. private class ConnectThread extends Thread {  
  2.     private final BluetoothSocket mmSocket;  
  3.     private final BluetoothDevice mmDevice;  
  4.   
  5.     public ConnectThread(BluetoothDevice device) {  
  6.         // Use a temporary object that is later assigned to mmSocket,  
  7.         // because mmSocket is final  
  8.         BluetoothSocket tmp = null;  
  9.         mmDevice = device;  
  10.   
  11.         // Get a BluetoothSocket to connect with the given BluetoothDevice  
  12.         try {  
  13.             // MY_UUID is the app's UUID string, also used by the server code  
  14.             tmp = device.createRfcommSocketToServiceRecord(MY_UUID);  
  15.         } catch (IOException e) { }  
  16.         mmSocket = tmp;  
  17.     }  
  18.   
  19.     public void run() {  
  20.         // Cancel discovery because it will slow down the connection  
  21.         mBluetoothAdapter.cancelDiscovery();  
  22.   
  23.         try {  
  24.             // Connect the device through the socket. This will block  
  25.             // until it succeeds or throws an exception  
  26.             mmSocket.connect();  
  27.         } catch (IOException connectException) {  
  28.             // Unable to connect; close the socket and get out  
  29.             try {  
  30.                 mmSocket.close();  
  31.             } catch (IOException closeException) { }  
  32.             return;  
  33.         }  
  34.   
  35.         // Do work to manage the connection (in a separate thread)  
  36.         manageConnectedSocket(mmSocket);  
  37.     }  
  38.   
  39.     /** Will cancel an in-progress connection, and close the socket */  
  40.     public void cancel() {  
  41.         try {  
  42.             mmSocket.close();  
  43.         } catch (IOException e) { }  
  44.     }  
  45. }  


注意:

1.两边的UUID必须是一样的,这是一个服务的唯一标识,关于公用UUID请看 公用UUID列表

http://blog.csdn.net/blueangle17/article/details/9670517


连接管理(数据通信)

分别通过BluetoothSocket的getInputStream()和getOutputStream()方法获取InputStream和OutputStream

使用read(bytes[])和write(bytes[])方法分别进行读写操作

注意:read(bytes[])方法会一直block,知道从流中读取到信息,而write(bytes[])方法并不是经常的block(比如在另一设备没有及时read或者中间缓冲区已满的情况下,write方法会block)

[java]  view plain copy
  1. private class ConnectedThread extends Thread {  
  2.     private final BluetoothSocket mmSocket;  
  3.     private final InputStream mmInStream;  
  4.     private final OutputStream mmOutStream;  
  5.   
  6.     public ConnectedThread(BluetoothSocket socket) {  
  7.         mmSocket = socket;  
  8.         InputStream tmpIn = null;  
  9.         OutputStream tmpOut = null;  
  10.   
  11.         // Get the input and output streams, using temp objects because  
  12.         // member streams are final  
  13.         try {  
  14.             tmpIn = socket.getInputStream();  
  15.             tmpOut = socket.getOutputStream();  
  16.         } catch (IOException e) { }  
  17.   
  18.         mmInStream = tmpIn;  
  19.         mmOutStream = tmpOut;  
  20.     }  
  21.   
  22.     public void run() {  
  23.         byte[] buffer = new byte[1024];  // buffer store for the stream  
  24.         int bytes; // bytes returned from read()  
  25.   
  26.         // Keep listening to the InputStream until an exception occurs  
  27.         while (true) {  
  28.             try {  
  29.                 // Read from the InputStream  
  30.                 bytes = mmInStream.read(buffer);  
  31.                 // Send the obtained bytes to the UI Activity  
  32.                 mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)  
  33.                         .sendToTarget();  
  34.             } catch (IOException e) {  
  35.                 break;  
  36.             }  
  37.         }  
  38.     }  
  39.   
  40.     /* Call this from the main Activity to send data to the remote device */  
  41.     public void write(byte[] bytes) {  
  42.         try {  
  43.             mmOutStream.write(bytes);  
  44.         } catch (IOException e) { }  
  45.     }  
  46.   
  47.     /* Call this from the main Activity to shutdown the connection */  
  48.     public void cancel() {  
  49.         try {  
  50.             mmSocket.close();  
  51.         } catch (IOException e) { }  
  52.     }  
  53. }  

该模块使用两个Service(服务器段Serivce和客户端Service)来分别控制服务器端和客户端的蓝牙通讯。

每个Service控制着若干线程

Service与其下属线程之间使用Handler进行通讯

Service与Activity之间的通讯使用Broadcast(广播)进行通讯

需要传递的数据通过一个自定义数据实体来进行传递


结构图:



通过Broadcast进行通讯的Action介绍:


服务器端Action列表:(同公用Action列表)

 

服务器与客户端公用Action列表:

 

ACTION_STOP_SERVICE:关闭后台服务。当程序退出或需要停止蓝牙服务时发送此广播

 

ACTION_DATA_TO_SERVICE:数据传送至后台Service。包含一个key为DATA的参数,该参数类型为实现了Serializable接口的类(该类为用户自己编写的数据实体类)。

 

ACTION_CONNECT_SUCCESS:连接成功。从后台Service发送出连接成功建立的广播。

 

ACTION_CONNECT_ERROR:连接错误。从后台Serivce发送出连接发生错误的广播。

 

ACTION_DATA_TO_GAME:从后台Service传送出数据。包含一个key为DATA的参数,该参数类型为实现了Serializable接口的类(该类为用户自己编写的数据实体类)。

 

客户端Action列表:

 

ACTION_START_DISCOVERY:开启蓝牙搜索。命令后台Service开始蓝牙搜索。

 

ACTION_SELECTED_DEVICE:选中的蓝牙设备。包含一个key为DEVICE的参数,该参数类型为BluetoothDevice(蓝牙设备类)。

用户需要从搜索到的蓝牙设备中选择服务器设备,选择设备后发送Broadcast,告知后台Service选择的蓝牙设备。

 

ACTION_FOUND_DEVICE:发现设备。后台Service进行搜索蓝牙设备过程中,每发现一个设备便会发送该Broadcast。

 

ACTION_NOT_FOUND_SERVER:未发现服务器设备。后台Service通过搜索并未发现可连接的蓝牙设备,发送此Broadcast。


蓝牙通讯模块源码及使用说明(下载链接)


CSDN下载链接(小弟没有资源分了,如果恰好您资源分多并且您想援助我一下就点此下载,需要资源分2分)

http://download.csdn.net/detail/gd920129/4289965   蓝牙通讯模块源码.zip

http://download.csdn.net/detail/gd920129/4290014   用于测试的源码(解压后为Eclipse工程文件夹,可直接导入使用。由于时间紧,测试代码并不完善,主要还是看我是如何使用通讯模块的)


华为网盘下载链接(资源同上,但是免费~~,╮(╯▽╰)╭ 同为无分人,相煎何太急~~~)

http://dl.vmall.com/c0zby6r7u9         蓝牙通讯模块源码.zip

http://dl.vmall.com/c04ph761cm             用于测试的源码(解压后为Eclipse工程文件夹,可直接导入使用。由于时间紧,测试代码并不完善,主要还是看我是如何使用通讯模块的)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android蓝牙开发浅析 的相关文章

  • 如何快速自动发送FCM或APNS消息?

    我正在开发一项后端服务 通过 FCM 或 APNS 向移动应用程序发送推送通知 我想创建一个可以在一分钟内运行的自动化测试 并验证服务器是否可以成功发送通知 请注意 我不一定需要检查通知是否已送达 只需检查 FCM 或 APNS 是否已成功
  • 在 ViewPager Fragments 中使用 Master/Detail 模板(下载链接)

    工作代码 https github com lukeallison ViewPagerMasterDetail https github com lukeallison ViewPagerMasterDetail Android 主 详细流
  • 找不到 com.google.firebase:firebase-core:9.0.0 [重复]

    这个问题在这里已经有答案了 在遵循有些不一致的指示之后here https firebase google com docs admob android quick start name your project and here http
  • CardView 圆角获得意想不到的白色

    When using rounded corner in CardView shows a white border in rounded area which is mostly visible in dark environment F
  • Android 模拟器插件无法初始化后端 EGL 显示

    我在 Cloudbees 上设置了 Jenkins 作业 并且可以在那里成功签出并编译我的 Android 项目 现在我想在 android 模拟器中运行一些 JUnit 测试并添加 Android 模拟器插件 我将 显示模拟器窗口 选项设
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 是否必须删除 Intent extra?

    这可能是一个愚蠢的问题 但是是否有一条规则规定消费活动必须显式删除 Intent 额外内容 或者只有在回收 Intent 对象时才如此 换句话说 如果我总是通过执行以下操作来链接到下一个活动 Intent i new Intent MyCu
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • 原色(有时)变得透明

    我正在使用最新的 SDK 版本 API 21 和支持库 21 0 2 进行开发 并且在尝试实施新的材料设计指南时遇到了麻烦 材料设计说我需要有我的primary color and my accent color并将它们应用到我的应用程序上
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • .isProviderEnabled(LocationManager.NETWORK_PROVIDER) 在 Android 中始终为 true

    我不知道为什么 但我的变量isNetowrkEnabled总是返回 true 我的设备上是否启用互联网并不重要 这是我的GPSTracker class public class GPSTracker extends Service imp
  • 一次显示两条Toast消息?

    我希望在一个位置显示一条 Toast 消息 并在另一位置同时显示另一条 Toast 消息 多个 Toast 消息似乎总是按顺序排队和显示 是否可以同时显示两条消息 是否有一种解决方法至少可以提供这种外观并且不涉及扰乱活动布局 Edit 看来
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • 将两个文本视图并排放置在布局中

    我有两个文本视图 需要在布局中并排放置 并且必须遵守两条规则 Textview2 始终需要完整显示 如果布局中没有足够的空间 则必须裁剪 Textview1 例子 文本视图1 文本视图2 Teeeeeeeeeeeeeeeeeextview1
  • 强制 Listview 不重复使用视图(复选框)

    我做了一个定制Listview 没有覆盖getView 方法 Listview 中的每个项目都具有以下布局 联系布局 xml

随机推荐

  • python词频统计_Python中文词频统计

    1 下载一长篇中文小说 2 从文件读取待分析文本 3 安装并使用jieba进行中文分词 pip install jieba import jieba ljieba lcut text import jieba txt open r piao
  • async 和 await

    async async是一个加在函数前面的修饰符 被async修饰的函数会默认返回一个promise对象 可以使用then方法添加回调函数 返回的promise对象的结果是由async函数执行的返回值的结果来决定的 1 当async函数内部
  • 一步步教你用 WebVR 实现虚拟现实游戏

    翻译 疯狂的技术宅 www smashingmagazine com 2018 11 vir 在本教程中 我们将创建三维对象并为它们添加简单的交互 此外 你还可以学到如何在客户端和服务器之间建立简单的消息传递系统 虚拟现实 VR 是一种依赖
  • 说说HashMap的扩容机制

    HashMap的扩容机制 HashMap的数据结构 HashMap几个重要的元素 HashMap的扩容过程 1 为什么扩容 2 什么时候进行扩容 3 怎么扩容 HashMap的数据结构 JDK1 8为例 如图 先知道三个概念 table 存
  • Vmware安装Ubuntu出现 unable to find a medium containing a live file system

    一 前言 由于未知的原因 使用Vmware安装Ubuntu的时候 总是遇到奇怪的问题 忘记截图了 大致是 unable to find a medium containing a live file system 找了几个帖子 参考1 参考
  • ajax 调用node,Node.js 远程调用 方法大全

    关于Node js 远程调用 远程调用 简称 RPC 主要是指服务器或集群之间对处理过程的调用 通过远程调用可以打通不同系统之间的数据与功能 或是抽离与建立公共的逻辑统一提供服务 远程调用的两端也称为远程调用的客户端与服务端 一般是多对多的
  • 借助模糊逻辑将文化算法与和谐搜索相结合进行学习——文化和谐学习算法(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 Matlab代码实现 4 参考文献 1 概述 文化和谐学习算法 创建于 18 Jan 2
  • 剑指 Offer 24. 反转链表

    定义一个函数 输入一个链表的头节点 反转该链表并输出反转后链表的头节点 示例 输入 1 gt 2 gt 3 gt 4 gt 5 gt NULL 输出 5 gt 4 gt 3 gt 2 gt 1 gt NULL 代码 Definition f
  • exchange 系统管理器 服务器,在“exchange系统管理器”安全里有个receive as是什么权限?谢谢...

    您好 用Visual Basic访问Microsoft Exchange和Outlook的数据 想通过Access中的Visual Basic for Applications VBA 和数据访问对象 DAO 的方法和对象来连接和导入来自E
  • 故事板(Storyboard)

    1 使用Storyboard完成各项常见功能 1 1 问题 故事板Storyboard是IOS5开始引入的一个新的系统 将多个视图文件 类似xib文件 集中到一个单独的可视化工作区间 负责创建和管理所有的界面及界面间的跳转 每一个Story
  • 【Log日志】springboot项目中集成Log日志详解

    springboot项目中集成Log日志详解 一 Log日志介绍 1 Log 日志组件主要作用及用途 2 日志的级别Level 级别控制 3 日志的输出Import 3 1 快速使用 3 2 日志文件输出 3 3 自定义配置 4 Sprin
  • 微派三轮面试总结

    三轮技术面 面试周期 2023 6 19 2023 6 26 目录 一面 1 介绍一下自己的项目 2 Vue2中父子组件的声明周期执行顺序是怎么样的 3 computed和watch的区别 4 Vue路由中包含两种模式 hash和histo
  • 在windows中使用scp命令

    windows自带scp命令 上传文件 使用方法 scp 源文件路径 账户 地址 目的路径 scp C Users zbh Desktop 1 txt lucas 192 168 11 150 home lucas 然后输入密码即可 下载文
  • React18的useEffect会执行两次

    React18的useEffect会执行两次 useeffect执行两次 翼晗的博客 CSDN博客
  • ubuntu20.04开启SSH远程登录

    默认情况下 首次安装Ubuntu时 不允许通过SSH进行远程访问 以root 用户或具有sudo特权的用户执行以下步骤 以在Ubuntu系统上安装并启用SSH 1 打开终端并安装openssh server软件包 sudo apt upda
  • 入门级动态规划:2018年第九届蓝桥杯省赛B组第四题—测试次数( 摔手机 )

    目录 下面列出用动态规划如何解决此问题 计算若干层楼用若干部手机最少需要摔多少次 计算用若干部手机摔若干次最多可以确定多少层楼 原题描述 x星球的居民脾气不太好 但好在他们生气的时候唯一的异常举动是 摔手机 各大厂商也就纷纷推出各种耐摔型手
  • IntelliJ IDEA中创建jsp项目

    原 IntelliJ IDEA中创建jsp项目 2019年06月13日 22 24 08 炸天帮陈长生 阅读数 88 更多 分类专栏 IDEA 版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和
  • SpringBoot集成ffmpeg、javacv自动为视频生成动态封面和静态封面图片

    引入依赖
  • 根据电子设计大赛心率检测的设计实践思路

    该装置具有以下几个特征 1 电路简单 系统整体功耗低 发热量低 可以稳定连续运行 2 使用新型 主频高的控制芯片 能在芯片上实现数据滤波 3 设计安卓端上位机显示心电信号与反馈信息 4 PC端上位机显示信号波形 将采集的数据以文件格式储存
  • Android蓝牙开发浅析

    由于近期正在开发一个通过蓝牙进行数据传递的模块 在参考了有关资料 并详细阅读了Android的官方文档后 总结了Android中蓝牙模块的使用 更新 之前承诺的蓝牙通讯模块的源码已经放出 详情请点击一下链接 http blog csdn n