手机应用开发之如何利用蓝牙与HC-05通信?

news2024/10/6 22:25:30

文章目录

  • 0、引言
  • 1、创建工程
  • 2、准备真机调试
  • 3、应用布局
  • 4、代码编写
  • 5、功能演示

0、引言

  本文通过AndroidStudio开发手机应用软件,实现蓝牙连接功能,并且能发送消息给HC-05蓝牙,也能接收HC-05回传的消息。本文在【AndroidStudio如何进行手机应用开发?】一文的基础上,进行了一次总结性应用,以下阐述工程建立过程,最终给出应用展示。

1、创建工程

  在这里插入图片描述

2、准备真机调试

  (1)手机打开允许USB调试
  在这里插入图片描述

  (2)数据线连接手机和电脑
  在这里插入图片描述

  (3)Android Studio显示手机设备
  在这里插入图片描述

3、应用布局

  在这里插入图片描述

  activity_main.xml

<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"  
xmlns:app="http://schemas.android.com/apk/res-auto"  
xmlns:tools="http://schemas.android.com/tools"  
android:layout_width="match_parent"  
android:layout_height="match_parent"  
android:orientation="vertical">  
  
<Button  
android:id="@+id/btn_linkBlueTooth"  
android:layout_width="match_parent"  
android:layout_height="wrap_content"  
android:onClick="linkBlueTooth"  
android:text="连接蓝牙"  
android:textSize="12sp"/>  
  
<TextView  
android:id="@+id/tv_blueToothStatus"  
android:layout_width="wrap_content"  
android:layout_height="wrap_content"  
android:layout_margin="10dp"  
android:text="蓝牙状态:未连接"  
android:textSize="18sp"/>  
  
<TextView  
android:layout_width="wrap_content"  
android:layout_height="wrap_content"  
android:layout_margin="10dp"  
android:text="接收消息:"  
android:textSize="18sp"/>  
  
<EditText  
android:id="@+id/etxt_receiveMessage"  
android:layout_width="match_parent"  
android:layout_height="200dp"  
android:background="@android:drawable/editbox_background"  
android:gravity="top"  
android:scrollbars="vertical"  
android:singleLine="false"  
android:focusable="false"  
android:editable="false"  
android:text=""  
android:textSize="18sp"/>  
  
<TextView  
android:layout_width="wrap_content"  
android:layout_height="wrap_content"  
android:layout_margin="10dp"  
android:text="发送消息:"  
android:textSize="18sp"/>  
  
<EditText  
android:id="@+id/etxt_sendMessage"  
android:layout_width="match_parent"  
android:layout_height="wrap_content"  
android:background="@android:drawable/editbox_background"  
android:text=""  
android:textSize="18sp"  
tools:ignore="SpeakableTextPresentCheck"/>  
  
<Button  
android:id="@+id/btn_send"  
android:layout_width="match_parent"  
android:layout_height="wrap_content"  
android:onClick="send"  
android:text="发送"  
android:textSize="12sp"/>  
</LinearLayout>

4、代码编写

  (1)添加蓝牙权限
  在这里插入图片描述

<uses-permissionandroid:name="android.permission.BLUETOOTH"/>
<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN"/>  
<uses-permissionandroid:name="android.permission.BLUETOOTH_CONNECT"/>  
<uses-permissionandroid:name="android.permission.BLUETOOTH_SCAN"/>  
<uses-permissionandroid:name="ohos.permission.DISCOVER_BLUETOOTH"/>

  (2)BluetoothChatUtil.java

packagecom.example.blcommunicate;
  
importandroid.bluetooth.BluetoothAdapter;  
importandroid.bluetooth.BluetoothDevice;  
importandroid.bluetooth.BluetoothServerSocket;  
importandroid.bluetooth.BluetoothSocket;  
importandroid.content.Context;  
importandroid.os.Bundle;  
importandroid.os.Handler;  
importandroid.os.Message;  
importandroid.util.Log;  
  
importjava.io.ByteArrayInputStream;  
importjava.io.DataInputStream;  
importjava.io.IOException;  
importjava.io.InputStream;  
importjava.io.OutputStream;  
importjava.util.UUID;  
  
/**  
*该类的工作:建立和管理蓝牙连接。  
*共有三个线程。mAcceptThread线程用来监听socket连接(服务端使用).  
*mConnectThread线程用来连接serversocket(客户端使用)。  
*mConnectedThread线程用来处理socket发送、接收数据。(客户端和服务端共用)  
*/  
publicclassBluetoothChatUtil{  
privatestaticfinalStringTAG="BluetoothChatClient";  
privatestaticfinalbooleanD=true;  
  
//服务名SDP  
privatestaticfinalStringSERVICE_NAME="BluetoothChat";  
//uuidSDP  
privatestaticfinalUUIDSERVICE_UUID=UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");  
//蓝牙适配器  
privatefinalBluetoothAdaptermAdapter;  
privateHandlermHandler;  
privateAcceptThreadmAcceptThread;  
  
privateConnectThreadmConnectThread;  
privateConnectedThreadmConnectedThread;  
  
privateintmState;  
privatestaticBluetoothChatUtilmBluetoothChatUtil;  
privateBluetoothDevicemConnectedBluetoothDevice;  
//常数,指示当前的连接状态  
publicstaticfinalintSTATE_NONE=0;//当前没有可用的连接  
publicstaticfinalintSTATE_LISTEN=1;//现在侦听传入的连接  
publicstaticfinalintSTATE_CONNECTING=2;//现在开始连接  
publicstaticfinalintSTATE_CONNECTED=3;//现在连接到远程设备  
publicstaticfinalintSTATAE_CONNECT_FAILURE=4;//连接失败  
publicstaticfinalintMESSAGE_DISCONNECTED=5;//断开连接  
publicstaticfinalintSTATE_CHANGE=6;//连接状态改变  
publicstaticfinalintMESSAGE_READ=7;  
publicstaticfinalintMESSAGE_WRITE=8;  
  
publicstaticfinalStringDEVICE_NAME="device_name";  
publicstaticfinalStringREAD_MSG="read_msg";  
  
/**  
*构造函数。准备一个新的bluetoothchat会话。  
*@paramcontext  
*/  
privateBluetoothChatUtil(Contextcontext){  
mAdapter=BluetoothAdapter.getDefaultAdapter();  
mState=STATE_NONE;  
}  
  
publicstaticBluetoothChatUtilgetInstance(Contextc){  
if(null==mBluetoothChatUtil){  
mBluetoothChatUtil=newBluetoothChatUtil(c);  
}  
returnmBluetoothChatUtil;  
}  
  
publicvoidregisterHandler(Handlerhandler){  
mHandler=handler;  
}  
  
publicvoidunregisterHandler(){  
mHandler=null;  
}  
  
/**  
*设置当前状态的聊天连接  
*@paramstate整数定义当前连接状态  
*/  
privatesynchronizedvoidsetState(intstate){  
if(D)Log.d(TAG,"setState()"+mState+"->"+state);  
mState=state;  
//给新状态的处理程序,界面活性可以更新  
mHandler.obtainMessage(STATE_CHANGE,state,-1).sendToTarget();  
}  
  
/**  
*返回当前的连接状态。*/  
publicsynchronizedintgetState(){  
returnmState;  
}  
  
publicBluetoothDevicegetConnectedDevice(){  
returnmConnectedBluetoothDevice;  
}  
  
/**  
*开始聊天服务。特别acceptthread开始  
*开始服务器模式。*/  
publicsynchronizedvoidstartListen(){  
if(D)Log.d(TAG,"start");  
//取消任何线程正在运行的连接  
if(mConnectedThread!=null){  
mConnectedThread.cancel();  
mConnectedThread=null;  
}  
//启动线程来监听一个bluetoothserversocket  
if(mAcceptThread==null){  
mAcceptThread=newAcceptThread();  
mAcceptThread.start();  
}  
setState(STATE_LISTEN);  
}  
  
/**  
*开始connectthread启动连接到远程设备。  
*@paramdevice连接的蓝牙设备  
*/  
publicsynchronizedvoidconnect(BluetoothDevicedevice){  
if(D)Log.d(TAG,"connectto:"+device);  
//取消任何线程试图建立连接  
if(mState==STATE_CONNECTING){  
if(mConnectThread!=null){  
mConnectThread.cancel();  
mConnectThread=null;  
}  
}  
//取消任何线程正在运行的连接  
if(mConnectedThread!=null){  
mConnectedThread.cancel();  
mConnectedThread=null;  
}  
//启动线程连接到远程设备  
mConnectThread=newConnectThread(device);  
mConnectThread.start();  
setState(STATE_CONNECTING);  
}  
  
/**  
*开始ConnectedThread开始管理一个蓝牙连接,传输、接收数据.  
*@paramsocketsocket连接  
*@paramdevice已连接的蓝牙设备  
*/  
publicsynchronizedvoidconnected(BluetoothSocketsocket,BluetoothDevicedevice){  
if(D)Log.d(TAG,"connected");  
//取消任何线程正在运行的连接  
if(mConnectedThread!=null){  
mConnectedThread.cancel();  
mConnectedThread=null;  
}  
//启动线程管理连接和传输  
mConnectedThread=newConnectedThread(socket);  
mConnectedThread.start();  
//把连接设备的名字传到uiActivity  
mConnectedBluetoothDevice=device;  
Messagemsg=mHandler.obtainMessage(STATE_CONNECTED);  
Bundlebundle=newBundle();  
bundle.putString(DEVICE_NAME,device.getName());  
msg.setData(bundle);  
mHandler.sendMessage(msg);  
setState(STATE_CONNECTED);  
}  
  
/**  
*停止所有的线程  
*/  
publicsynchronizedvoiddisconnect(){  
if(D)Log.d(TAG,"disconnect");  
if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}  
if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}  
if(mAcceptThread!=null){mAcceptThread.cancel();mAcceptThread=null;}  
setState(STATE_NONE);  
}  
  
/**  
*WritetotheConnectedThreadinanunsynchronizedmanner  
*@paramoutThebytestowrite  
*@seeConnectedThread#write(byte[])  
*/  
publicvoidwrite(byte[]out){  
//创建临时对象  
ConnectedThreadr;  
//同步副本的connectedthread  
synchronized(this){  
if(mState!=STATE_CONNECTED)return;  
r=mConnectedThread;  
}  
//执行写同步  
r.write(out);  
}  
/**  
*IndicatethattheconnectionattemptfailedandnotifytheUIActivity.  
*/  
privatevoidconnectionFailed(){  
//发送失败的信息带回活动  
Messagemsg=mHandler.obtainMessage(STATAE_CONNECT_FAILURE);  
mHandler.sendMessage(msg);  
mConnectedBluetoothDevice=null;  
setState(STATE_NONE);  
}  
  
/**  
*IndicatethattheconnectionwaslostandnotifytheUIActivity.  
*/  
publicvoidconnectionLost(){  
//发送失败的信息带回Activity  
Messagemsg=mHandler.obtainMessage(MESSAGE_DISCONNECTED);  
mHandler.sendMessage(msg);  
mConnectedBluetoothDevice=null;  
setState(STATE_NONE);  
}  
  
/**  
*本线程侦听传入的连接。  
*它运行直到连接被接受(或取消)。  
*/  
privateclassAcceptThreadextendsThread{  
//本地服务器套接字  
privatefinalBluetoothServerSocketmServerSocket;  
publicAcceptThread(){  
BluetoothServerSockettmp=null;  
//创建一个新的侦听服务器套接字  
try{  
tmp=mAdapter.listenUsingRfcommWithServiceRecord(  
SERVICE_NAME,SERVICE_UUID);  
//tmp=mAdapter.listenUsingInsecureRfcommWithServiceRecord(SERVICE_NAME,SERVICE_UUID);  
}catch(IOExceptione){  
Log.e(TAG,"listen()failed",e);  
}  
mServerSocket=tmp;  
}  
  
publicvoidrun(){  
if(D)Log.d(TAG,"BEGINmAcceptThread"+this);  
setName("AcceptThread");  
BluetoothSocketsocket=null;  
//循环,直到连接成功  
while(mState!=STATE_CONNECTED){  
try{  
//这是一个阻塞调用返回成功的连接  
//mServerSocket.close()在另一个线程中调用,可以中止该阻塞  
socket=mServerSocket.accept();  
}catch(IOExceptione){  
Log.e(TAG,"accept()failed",e);  
break;  
}  
//如果连接被接受  
if(socket!=null){  
synchronized(BluetoothChatUtil.this){  
switch(mState){  
caseSTATE_LISTEN:  
caseSTATE_CONNECTING:  
//正常情况。启动ConnectedThread。  
connected(socket,socket.getRemoteDevice());  
break;  
caseSTATE_NONE:  
caseSTATE_CONNECTED:  
//没有准备或已连接。新连接终止。  
try{  
socket.close();  
}catch(IOExceptione){  
Log.e(TAG,"Couldnotcloseunwantedsocket",e);  
}  
break;  
}  
}  
}  
}  
if(D)Log.i(TAG,"ENDmAcceptThread");  
}  
  
publicvoidcancel(){  
if(D)Log.d(TAG,"cancel"+this);  
try{  
mServerSocket.close();  
}catch(IOExceptione){  
Log.e(TAG,"close()ofserverfailed",e);  
}  
}  
}  
/**  
*本线程用来连接设备  
*  
*/  
privateclassConnectThreadextendsThread{  
privateBluetoothSocketmmSocket;  
privatefinalBluetoothDevicemmDevice;  
publicConnectThread(BluetoothDevicedevice){  
mmDevice=device;  
BluetoothSockettmp=null;  
//得到一个bluetoothsocket  
try{  
mmSocket=device.createRfcommSocketToServiceRecord  
(SERVICE_UUID);  
}catch(IOExceptione){  
Log.e(TAG,"create()failed",e);  
mmSocket=null;  
}  
}  
  
publicvoidrun(){  
Log.i(TAG,"BEGINmConnectThread");  
try{  
//socket连接,该调用会阻塞,直到连接成功或失败  
mmSocket.connect();  
}catch(IOExceptione){  
Log.e(TAG,"IOException");  
connectionFailed();  
try{//关闭这个socket  
mmSocket.close();  
}catch(IOExceptione2){  
e2.printStackTrace();  
}  
return;  
}  
//启动连接线程  
connected(mmSocket,mmDevice);  
}  
  
publicvoidcancel(){  
try{  
mmSocket.close();  
}catch(IOExceptione){  
Log.e(TAG,"close()ofconnectsocketfailed",e);  
}  
}  
}  
  
/**  
*本线程server和client共用.  
*它处理所有传入和传出的数据。  
*/  
privateclassConnectedThreadextendsThread{  
privatefinalBluetoothSocketmmSocket;  
privatefinalInputStreammmInStream;  
privatefinalOutputStreammmOutStream;  
  
publicConnectedThread(BluetoothSocketsocket){  
Log.d(TAG,"createConnectedThread");  
mmSocket=socket;  
InputStreamtmpIn=null;  
OutputStreamtmpOut=null;  
//获得bluetoothsocket输入输出流  
try{  
tmpIn=socket.getInputStream();  
tmpOut=socket.getOutputStream();  
}catch(IOExceptione){  
Log.e(TAG,"没有创建临时sockets",e);  
}  
mmInStream=tmpIn;  
mmOutStream=tmpOut;  
}  
  
publicvoidrun(){  
//监听输入流  
while(true){  
try{  
byte[]buffer=newbyte[512];  
//读取输入流  
intbytes=mmInStream.read(buffer);  
//发送获得的字节的uiactivity  
Messagemsg=mHandler.obtainMessage(MESSAGE_READ);  
Bundlebundle=newBundle();  
bundle.putByteArray(READ_MSG,buffer);  
msg.setData(bundle);  
mHandler.sendMessage(msg);  
}catch(IOExceptione){  
Log.e(TAG,"disconnected",e);  
connectionLost();  
break;  
}  
}  
}  
  
/**  
*向外发送。  
*@parambuffer发送的数据  
*/  
publicvoidwrite(byte[]buffer){  
try{  
mmOutStream.write(buffer);  
//分享发送的信息到Activity  
mHandler.obtainMessage(MESSAGE_WRITE,-1,-1,buffer)  
.sendToTarget();  
}catch(IOExceptione){  
Log.e(TAG,"Exceptionduringwrite",e);  
}  
}  
  
publicvoidcancel(){  
try{  
mmSocket.close();  
}catch(IOExceptione){  
Log.e(TAG,"close()ofconnectsocketfailed",e);  
}  
}  
}  
  
publicstaticintByteArrayToInt(byteb[])throwsException{  
ByteArrayInputStreambuf=newByteArrayInputStream(b);  
DataInputStreamdis=newDataInputStream(buf);  
returndis.readInt();  
}  
}

  (3)MainActivity.java

packagecom.example.blcommunicate;
  
importandroidx.annotation.RequiresApi;  
importandroidx.appcompat.app.AppCompatActivity;  
importandroidx.core.app.ActivityCompat;  
  
importandroid.Manifest;  
importandroid.annotation.SuppressLint;  
importandroid.bluetooth.BluetoothAdapter;  
importandroid.bluetooth.BluetoothDevice;  
importandroid.content.IntentFilter;  
importandroid.content.pm.PackageManager;  
importandroid.os.Build;  
importandroid.os.Bundle;  
importandroid.os.Environment;  
importandroid.os.Handler;  
importandroid.os.Message;  
importandroid.text.method.ScrollingMovementMethod;  
importandroid.util.Log;  
importandroid.view.View;  
importandroid.widget.AdapterView;  
importandroid.widget.ArrayAdapter;  
importandroid.widget.Button;  
importandroid.widget.EditText;  
importandroid.widget.ListView;  
importandroid.widget.TextView;  
importandroid.widget.Toast;  
  
importjava.io.File;  
importjava.io.IOException;  
importjava.text.SimpleDateFormat;  
importjava.util.ArrayList;  
importjava.util.Date;  
importjava.util.Set;  
  
publicclassMainActivityextendsAppCompatActivity{  
TextViewtv_blueToothStatus;  
Buttonbtn_linkBlueTooth;  
Buttonbtn_send;  
EditTextetxt_receiveMessage;  
EditTextetxt_sendMessage;  
privateBluetoothAdapterbluetoothAdapter;  
BluetoothChatUtilmBlthChatUtil;  
booleanreadOver=true;  
StringstrGet="";  
  
@Override  
protectedvoidonCreate(BundlesavedInstanceState){  
super.onCreate(savedInstanceState);  
setContentView(R.layout.activity_main);  
  
tv_blueToothStatus=(TextView)findViewById(R.id.tv_blueToothStatus);  
btn_linkBlueTooth=(Button)findViewById(R.id.btn_linkBlueTooth);  
btn_send=(Button)findViewById(R.id.btn_send);  
etxt_receiveMessage=(EditText)findViewById(R.id.etxt_receiveMessage);  
etxt_sendMessage=(EditText)findViewById(R.id.etxt_sendMessage);  
  
if(isSupported()){  
Toast.makeText(this,"设备支持蓝牙",Toast.LENGTH_SHORT).show();  
}else{  
Toast.makeText(this,"设备不支持蓝牙",Toast.LENGTH_SHORT).show();  
}  
  
if(bluetoothAdapter.isEnabled()){  
//已经打开蓝牙,判断Android版本是否需要添加权限,解决:无法发现蓝牙设备的问题  
Toast.makeText(this,"蓝牙已打开",Toast.LENGTH_SHORT).show();  
getPermission();  
}else{  
//开启蓝牙  
if(ActivityCompat.checkSelfPermission(this,Manifest.permission.BLUETOOTH_CONNECT)!=PackageManager.PERMISSION_GRANTED){  
return;  
}  
bluetoothAdapter.enable();  
//关闭蓝牙:bluetoothAdapter.disable();  
}  
}  
  
/**  
*连接蓝牙  
*@paramview  
*/  
publicvoidlinkBlueTooth(Viewview){  
etxt_receiveMessage.setText("");  
mBlthChatUtil=BluetoothChatUtil.getInstance(this);  
mBlthChatUtil.registerHandler(mHandler);  
Set<BluetoothDevice>pairedDevices=bluetoothAdapter.getBondedDevices();  
if(pairedDevices.size()>0){  
//如果有配对的设备  
for(BluetoothDevicedevice:pairedDevices){  
//通过arrayadapter在列表中添加设备名称和地址  
if(device.getName().equals("HC-05")){  
if(bluetoothAdapter.isDiscovering()){  
//取消搜索  
bluetoothAdapter.cancelDiscovery();  
}  
if(mBlthChatUtil.getState()==BluetoothChatUtil.STATE_CONNECTED){  
showToast("蓝牙已连接");  
}else{  
mBlthChatUtil.connect(device);  
if(mBlthChatUtil.getState()==BluetoothChatUtil.STATE_CONNECTED){  
showToast("蓝牙连接成功");  
}  
}  
break;  
}  
}  
}else{  
showToast("暂无已配对设备");  
}  
}  
  
/**  
*发送  
*@paramview  
*/  
publicvoidsend(Viewview){  
byte[]buffer2=etxt_sendMessage.getText().toString().getBytes();  
mBlthChatUtil.write(buffer2);  
}  
  
/**  
*判断是否设备是否支持蓝牙  
*@return是否支持  
*/  
privatebooleanisSupported(){  
//初始化  
bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();  
if(bluetoothAdapter==null){  
returnfalse;  
}else{  
returntrue;  
}  
}  
  
/**  
*获取权限  
*/  
@SuppressLint("WrongConstant")  
privatevoidgetPermission(){  
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.M){  
intpermissionCheck=0;  
permissionCheck=this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);  
permissionCheck+=this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);  
  
if(permissionCheck!=PackageManager.PERMISSION_GRANTED){  
intACCESS_LOCATION=1;//自定义常量,任意整型  
//未获得权限  
this.requestPermissions(//请求授权  
newString[]{Manifest.permission.ACCESS_FINE_LOCATION,  
Manifest.permission.ACCESS_COARSE_LOCATION},  
ACCESS_LOCATION);  
}  
}  
}  
  
/**  
*显示消息  
*@paramstr  
*/  
privatevoidshowToast(Stringstr){  
Toast.makeText(this,str,Toast.LENGTH_SHORT).show();  
}  
  
/**  
*消息句柄  
*/  
privateHandlermHandler=newHandler(){  
@RequiresApi(api=Build.VERSION_CODES.R)  
@SuppressLint("HandlerLeak")  
publicvoidhandleMessage(Messagemsg){  
StringdeviceName=msg.getData().getString(BluetoothChatUtil.DEVICE_NAME);  
switch(msg.what){  
caseBluetoothChatUtil.STATE_CONNECTED:  
showToast("连接成功");  
tv_blueToothStatus.setText("蓝牙状态:已连接HC-05");  
break;  
caseBluetoothChatUtil.STATAE_CONNECT_FAILURE:  
showToast("连接失败");  
break;  
caseBluetoothChatUtil.STATE_CHANGE:  
showToast("正在连接设备..");  
break;  
caseBluetoothChatUtil.MESSAGE_DISCONNECTED:  
showToast("与设备断开连接");  
break;  
//读到另一方传送的消息  
caseBluetoothChatUtil.MESSAGE_READ:{  
//showToast("接收消息成功");  
byte[]buf;  
Stringstr;  
buf=msg.getData().getByteArray(BluetoothChatUtil.READ_MSG);  
str=newString(buf,0,buf.length);  
  
//根据HC-05传来的消息进行相应的处理后显示  
if(readOver){  
strGet=str.trim();  
if(strGet.length()<9){  
readOver=false;  
return;  
}  
}  
else{  
strGet+=str.trim();  
readOver=true;  
}  
etxt_receiveMessage.setText(etxt_receiveMessage.getText()+"\n"+strGet);  
break;  
}  
  
caseBluetoothChatUtil.MESSAGE_WRITE:{  
//showToast("发送消息成功");  
break;  
}  
default:  
break;  
}  
};  
};  
}

  注1:
  代码在笔者编译环境中会出现红色的权限检查报错提示,该错误不影响程序运行。
  在这里插入图片描述

  注2:
  本工程的代码文件参见:手机应用开发之如何利用蓝牙与HC-05通信?-工程代码;
  代码移植方法参见:AndroidStudio如何进行代码移植?。

5、功能演示

  (1)手机配对HC-05蓝牙
  在这里插入图片描述

  (2)软件功能演示
  在这里插入图片描述

参考资料:
[1] cacrle. AndroidStudio如何进行手机应用开发?; 2023-04-16 [accessed 2023-04-16].
[2] cacrle. AndroidStudio如何进行代码移植?; 2023-04-16 [accessed 2023-04-16].
[3] suda哇. Android Studio如何进行真机调试; 2020-05-24 [accessed 2023-04-16].
[4] 金胖. Android蓝牙扫描/连接/收发数据; 2019-03-26 [accessed 2023-04-16].
[5] 考研兔萌酱. android蓝牙传输信息,Android 蓝牙(BLE)连接,发送,接收消息; 2021-05-26 [accessed 2023-04-16].
[6] van久. Android-蓝牙通信; 2019-07-01 [accessed 2023-04-16].
[7] 停止的猪头. 编程回忆之Android回忆(蓝牙BluetoothAdapter的搜索和连接); 2014-02-27 [accessed 2023-04-16].
[8] Panner_pan. 蓝牙开发(二)扫描设备; 2018-09-11 [accessed 2023-04-16].
[9] MirkoWu. Android 低功耗蓝牙(BLE)开发(3)-- BluetoothDevice详解; 2016-12-24 [accessed 2023-04-16].
[10] 杨枝甘卢. 安卓开发实现蓝牙通信——两设备相互发消息; 2021-12-13 [accessed 2023-04-16].

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/418821.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++基础学习笔记(八)——提高编程PART3

参考链接&#xff1a;https://www.bilibili.com/video/BV1et411b73Z/p237&spm_id_frompageDriver&vd_sourceb4d9cee68649c8adcb1e266f7147cd5c 4 STL- 函数对象 4.1 函数对象 4.1.1 函数对象概念 概念&#xff1a; 重载函数调用操作符的类&#xff0c;其对象常称为…

STL的并行遍历:for_each(依赖TBB)和omp parallel

文章目录OMP parallelOpenMP安装OpenMP示例1) OMP Hello World2) OMP for 并行3. OMP 官方示例4) map使用OMP遍历TBB的安装和使用Gcc9的安装TBB 安装TBB使用在图像处理等应用中&#xff0c;我们经常需要对矩阵&#xff0c;大数量STL对象进行遍历操作&#xff0c;因此并行化对算…

R语言与作物模型(以DSSAT模型为例)融合应用

随着基于过程的作物生长模型&#xff08;Process-based Crop Growth Simulation Model&#xff09;的发展&#xff0c;R语言在作物生长模型和数据分析、挖掘和可视化中发挥着越来越重要的作用。想要成为一名优秀的作物模型使用者与科研团队不可或缺的人才&#xff0c;除了掌握对…

MySQL存储过程 if、case、while、loop、游标、变量、条件处理程序

存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合&#xff0c;调用存储过程可以简化很多工作&#xff0c;减少数据在数据库和应用服务器之间的传输&#xff0c;对于提高数据处理的效率是有好处的。 存储过程思想上很简单&#xff0c;就是数据库 SQL 语言层面的代…

barret reduction原理详解及硬件优化

背景介绍 约减算法&#xff0c;通常应用在硬件领域&#xff0c;因为模运算mod是一个除法运算&#xff0c;在硬件中实现速度会比乘法慢的多&#xff0c;并且还会占用大量资源&#xff0c;因此需要想办法用乘法及其它简单运算来替代模运算。模约减算法可以利用乘法、加法和移位等…

怎么评价2023年第十三届MathorCup高校数学建模挑战赛?

文章目录赛题思路选题建议1 竞赛信息2 竞赛时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; 选题建议 首先要注意&#xff0c;A、B题为研究生组可选题目&#xff0c;A…

还在用 if else 做参数校验?快来学习高级参数校验吧

文章目录一、前言二、自定义校验2.1 定义 GenderArrayValuable 接口2.2 定义性别 GenderEnum 枚举类2.3 自定义 GenderCheck 自定义约束注解2.4 自定义约束的校验器 GenderValidator2.5 定义 UserUpdateGenderDTO2.6 定义一个对外访问接口2.7 请求接口 进行验证三、总结一、前言…

从C出发 17 --- 函数调用

从表面上来看&#xff0c;函数就是一个代码片段&#xff0c;只不过说这个代码片段可以反复利用&#xff0c;通过调用的方式反复利用&#xff0c;通过函数调用&#xff0c;我们可以将参数传到函数所对应的代码片段里面&#xff0c;然后代码片段去处理这些参数&#xff0c;得到一…

Linux下Samba服务器的安装与配置(简单实用)

为了可以实现Linux与windows之间实现文件的共享&#xff0c;方便文件可以直接修改&#xff0c;而不是像以前需要拷贝文件再进行修改&#xff0c;samba的诞生是为了实现现在的这些需求。我们知道Linux之间可以使用NFS服务器来实现文件的共享&#xff0c;samba的诞生就是为了使wi…

Spring Cloud Security

Spring Cloud Security Spring Cloud Security用于构建微服务的安全应用程序和服务&#xff0c;它可以轻松实现微服务系统架构下的统一安全认证与授权。 Spring Cloud Security 有以下组件。 spring-cloud-security&#xff1a;为Zuul、Feign、Oauth 2.0 的Resource Serve…

ChatGPT5是否会影响人类的发展和工作?

目录前言ChatGPT5是什么ChatGPT5 的潜在影响挑战与风险总结前言 ChatGPT的普及也带来了大量的讨论&#xff0c;关于它是否会影响人类的发展和工作。本文将讨论 ChatGPT5 如何可能改变人类的工作和发展&#xff0c;以及潜在的利弊和挑战。在话题开始之前&#xff0c;让我们先从…

QxOrm的使用-数据操作--增删改查

文章目录QxOrm的使用-数据操作使用QxOrm对数据库进行增删改查新增数据删除数据修改数据查询数据QxOrm的使用-数据操作 上一篇我们讲了QxOrm的基本的数据映射操作&#xff0c;这里面再补充一点东西 数据类型映射 Qt/C类型数据库类型boolSMALLINTqx_boolSMALLINTshortSMALLINT…

【谷粒商城之整合阿里云OSS对象存储】

本笔记内容为尚硅谷谷粒商城整合阿里云OSS对象存储部分 目录 一 、简介 二、云存储开通与使用 1、开通阿里云对象存储服务 2、创建bucket 3、创建子用户&#xff08;获取密钥访问OSS服务器&#xff09; 给该子账户添加权限 4、阿里云对象存储上传方式 三、整合 1、…

BUUCTF--Web篇详细wp

BUUCTF--Web篇详细wp[极客大挑战 2019]EasySQL[极客大挑战 2019]Havefun[HCTF 2018]WarmUp[ACTF2020 新生赛]Include[ACTF2020 新生赛]Exec[强网杯 2019]随便注[GXYCTF2019]Ping Ping Ping[SUCTF 2019]EasySQL[极客大挑战 2019]Secret File[极客大挑战 2019]LoveSQL[极客大挑战…

MySQL 分布式数据库实现:无需修改代码,轻松实现分布式能力

这个项目做什么 ShardingSphere-Proxy&#xff0c;可以让用户像使用原生数据库一样使用 Apache ShardingSphere。 了解一项技术的开始&#xff0c;一般从官网开始。先来看一看官网对 ShardingSphere-Proxy 的定义是什么样的&#xff1a; 定位为透明化的数据库代理端&#xff…

异配图神经网络——Graph Transformer Networks

一.论文概述 作者提出了Graph Transformer Network (GTN)用来在异配图&#xff08;heterogeneous graph&#xff09;上学习节点表示。通过Graph Transformer层&#xff0c;模型能将异构图转换为由meta-path定义的多个新图&#xff0c;这些meta-paths具有任意的边类型和长度&am…

运行Spring Boot项目时[ java: 错误: 不支持发行版本 17 ]

项目场景&#xff1a; 使用IDEA的Spring Initializr构建的Spring boot项目在构建完成后运行出错 问题描述&#xff1a; 用Spring Initializr创建了Spring Boot 项目后&#xff0c;运行时报错&#xff1a; “错误:java: 错误: 不支持发行版本 17”根据错误信息得知&#xff…

Vue学习笔记(5. 计算属性,监视器(侦听器))

1. 计算属性&#xff08;computed&#xff09; (1) get方式 初期显示 改变值后&#xff08;hello -> hello1&#xff09;计算属性allStr跟随变更 (2) get set方式 页面初期显示 改变值&#xff08;hello -> hello1&#xff09;计算属性的get会监控到变更&#xff0c;使…

国产SSD、内存卷哭国外大厂,三星宣布减产涨价在路上了

PC 圈有一句话是这么说的&#xff1a;论价格屠夫还得看国产品牌&#xff01; 可不是嘛&#xff0c;国产长鑫、长江算是彻底将全球存储芯片市场搅局者这一「骂名」坐实了&#xff01; 不说特别早期&#xff0c;前几年吧&#xff0c;普通单条 8G DDR4 内存都能卖到六七百元&…

C++ 红黑树

1.红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路 径会比其他路径长出俩倍&#xff0c;因…