前些天学弟让我给他整理之前一起做项目时的与下位机通信的部分代码。当时使用蓝牙编程,Android端通过蓝牙发送指令到蓝牙模块,硬件那里通过蓝牙模块读取到指令,并执行相应操作。由于那段代码时在工程里的,抽取出来很麻烦。所以决定在网上找个实例就可以了,当时也是这样做的,但是找了半天,都只找到一个但需要5个积分,但是资源积分让我们这些学生很头疼,其实一共就三个文件(布局(放一些按钮),配置(添加一些权限),java(就一个一个(通过蓝牙模块的mac地址连接蓝牙,以及处理相应按钮事件(就是向蓝牙写入指令))),真心觉得积分太黑,所以特地写这blog ,还有如果有人真需要源码。可在评论处留言,我再发一个源码(但是当真不建议,如果直接给工程,大多数同学都是直接运行,如果正常就不管了。这对Android编程能力没好处,虽然你现在只是复制源代码,但是这也对你熟悉Android程序的结构有帮助啊。)。

Android是个开源的应用,使用Java语言对其编程。于是这次的开发我选用Eclipse作为开发工具,用Java语言开发手机端的控制程序,由于之前对Android的蓝牙通信这块涉及不多,一开始感觉有点小茫然,而网上也少有这方面的例程,所以特地处理了这博客,给那些需要的人 。把这些代码复制到Android工程里既可以完成功能了。记住必须把蓝牙mac地址改成自己蓝牙模块的。

下面开始介绍Android手机端控制程序的编写:

首先打开Eclipse,当然之前的Java开发环境和安卓开发工具自己得先配置好,这里就不多说了,网上教程一大摞。

然后新建一个Android项目,修改布局文件main.xml,代码如下:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <AbsoluteLayout
  3. android:id="@+id/widget0"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. xmlns:android="http://schemas.android.com/apk/res/android"
  7. >
  8. <Button
  9. android:id="@+id/btnF"
  10. android:layout_width="100px"
  11. android:layout_height="60px"
  12. android:text="前进"
  13. android:layout_x="130px"
  14. android:layout_y="62px"
  15. >
  16. </Button>
  17. <Button
  18. android:id="@+id/btnL"
  19. android:layout_width="100px"
  20. android:layout_height="60px"
  21. android:text="左转"
  22. android:layout_x="20px"
  23. android:layout_y="152px"
  24. >
  25. </Button>
  26. <Button
  27. android:id="@+id/btnR"
  28. android:layout_width="100px"
  29. android:layout_height="60px"
  30. android:text="右转"
  31. android:layout_x="240px"
  32. android:layout_y="152px"
  33. >
  34. </Button>
  35. <Button
  36. android:id="@+id/btnB"
  37. android:layout_width="100px"
  38. android:layout_height="60px"
  39. android:text="后退"
  40. android:layout_x="130px"
  41. android:layout_y="242px"
  42. >
  43. </Button>
  44. <Button
  45. android:id="@+id/btnS"
  46. android:layout_width="100px"
  47. android:layout_height="60px"
  48. android:text="停止"
  49. android:layout_x="130px"
  50. android:layout_y="152px"
  51. >
  52. </Button>
  53. </AbsoluteLayout>

这个布局文件的效果就是如视频中所示的手机操作界面。

然后是权限声明,这一步不能少,否则将无法使用安卓手机的蓝牙功能。

权限声明如下:

打开AndroidManifest.xml文件,修改代码如下:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.ThinBTClient.www"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  7. <uses-permission android:name="android.permission.BLUETOOTH" />
  8. <application android:icon="@drawable/icon" android:label="@string/app_name">
  9. <activity android:name=".ThinBTClient"
  10. android:label="@string/app_name">
  11. <intent-filter>
  12. <action android:name="android.intent.action.MAIN" />
  13. <category android:name="android.intent.category.LAUNCHER" />
  14. </intent-filter>
  15. </activity>
  16. </application>
  17. </manifest>

其中

  1. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  2. <uses-permission android:name="android.permission.BLUETOOTH" />

就是蓝牙相关权限。Android 里有严格的权限管理机制,写应用程序时必须加上相应权限,类似于访问网络的权限,访问sd卡权限等等很多很多,一般和硬件相关的(相机,传感器)都有相应权限。反正遇到编程时,要考虑到相应权限加了没。否则程序无法正常运行。后台日志会输出permission deny (权限拒绝) 的提示。

然后编写Activity中的执行代码,这些代码的作用就是发送指令,控制小车的运动。

代码如下:

package com.ThinBTClient.www;  
  
import android.app.Activity;  
import android.os.Bundle;  
import java.io.IOException;  
  
import java.io.OutputStream;  
import java.util.UUID;  
  
import android.app.Activity;  
  
import android.bluetooth.BluetoothAdapter;  
  
import android.bluetooth.BluetoothDevice;  
  
import android.bluetooth.BluetoothSocket;  
import android.content.DialogInterface;  
import android.content.DialogInterface.OnClickListener;  
  
import android.os.Bundle;  
import android.provider.ContactsContract.CommonDataKinds.Event;  
  
import android.util.Log;  
import android.view.MotionEvent;  
import android.view.View;  
  
import android.widget.Button;  
import android.widget.Toast;  
public class ThinBTClient extends Activity {  
private static final String TAG = "THINBTCLIENT";  
  
private static final boolean D = true;  
  
private BluetoothAdapter mBluetoothAdapter = null;  
  
private BluetoothSocket btSocket = null;  //手机蓝牙与蓝牙模块之间的socket
  
private OutputStream outStream = null;  //发送指令的输出流
Button mButtonF;  
  
Button mButtonB;  
Button mButtonL;  
Button mButtonR;  
Button mButtonS;  
  
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");  
  
  
private static String address = "00:11:03:21:00:43"; // <==要连接的蓝牙设备MAC地址  
  
  
/** Called when the activity is first created. */  
  
@Override  
  
public void onCreate(Bundle savedInstanceState) {  
  
super.onCreate(savedInstanceState);  
setContentView(R.layout.main);  
  
//前进  
mButtonF=(Button)findViewById(R.id.btnF);  
mButtonF.setOnTouchListener(new Button.OnTouchListener(){  
  
@Override  
public boolean onTouch(View v, MotionEvent event) {  
// TODO Auto-generated method stub  
String message;  
byte[] msgBuffer;  
int action = event.getAction();  
switch(action)  
{  
case MotionEvent.ACTION_DOWN:  //按下了前进按钮
try {  
outStream = btSocket.getOutputStream();  //通过socket 得到输出流
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "1";  //上位机与下位机约定的指令1表示前进
  
msgBuffer = message.getBytes();  //因为outputStream 只能传输字节,所以要把字符串指令编程字节流
  
try {  
outStream.write(msgBuffer);  //将指令写入输出流中。也就是写入socket中
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
  
case MotionEvent.ACTION_UP:  //松开了前进按钮,与前面类似,只是指令不同。
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "0";  
  
msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
}  
return false;  
}  
  
  
});  
//后退  
mButtonB=(Button)findViewById(R.id.btnB);  
mButtonB.setOnTouchListener(new Button.OnTouchListener(){  
  
  
@Override  
public boolean onTouch(View v, MotionEvent event) {  
// TODO Auto-generated method stub  
String message;  
byte[] msgBuffer;  
int action = event.getAction();  
switch(action)  
{  
case MotionEvent.ACTION_DOWN:  
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "3";  
  
msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
  
case MotionEvent.ACTION_UP:  
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "0";  
  
msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
}  
  
return false;  
}  
  
  
});  
//左转  
mButtonL=(Button)findViewById(R.id.btnL);  
mButtonL.setOnTouchListener(new Button.OnTouchListener(){  
  
@Override  
public boolean onTouch(View v, MotionEvent event) {  
// TODO Auto-generated method stub  
String message;  
byte[] msgBuffer;  
int action = event.getAction();  
switch(action)  
{  
case MotionEvent.ACTION_DOWN:  
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "2";  
  
msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
  
case MotionEvent.ACTION_UP:  
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "0";  
  
msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
}  
  
return false;  
  
}  
});  
//右转  
mButtonR=(Button)findViewById(R.id.btnR);  
mButtonR.setOnTouchListener(new Button.OnTouchListener(){  
  
@Override  
public boolean onTouch(View v, MotionEvent event) {  
// TODO Auto-generated method stub  
String message;  
byte[] msgBuffer;  
int action = event.getAction();  
switch(action)  
{  
case MotionEvent.ACTION_DOWN:  
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "4";  
  
msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
  
case MotionEvent.ACTION_UP:  
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
message = "0";  
  
msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
break;  
}  
  
return false;  
  
}  
  
  
});  
  
//停止  
mButtonS=(Button)findViewById(R.id.btnS);  
mButtonS.setOnTouchListener(new Button.OnTouchListener(){  
  
@Override  
public boolean onTouch(View v, MotionEvent event) {  
// TODO Auto-generated method stub  
if(event.getAction()==MotionEvent.ACTION_DOWN)  
try {  
outStream = btSocket.getOutputStream();  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);  
}  
  
  
String message = "0";  
  
byte[] msgBuffer = message.getBytes();  
  
try {  
outStream.write(msgBuffer);  
  
} catch (IOException e) {  
Log.e(TAG, "ON RESUME: Exception during write.", e);  
}  
return false;  
}  
  
  
});  
  
if (D)  
Log.e(TAG, "+++ ON CREATE +++");  
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  
if (mBluetoothAdapter == null) {  
Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show();  
finish();  
return;  
}  
  
  
if (!mBluetoothAdapter.isEnabled()) {  
Toast.makeText(this, "Please enable your Bluetooth and re-run this program.", Toast.LENGTH_LONG).show();  
finish();  
return;  
  
}  
  
  
if (D)  
Log.e(TAG, "+++ DONE IN ON CREATE, GOT LOCAL BT ADAPTER +++");  
  
}  
  
  
@Override  
  
public void onStart() {  
  
super.onStart();  
  
if (D) Log.e(TAG, "++ ON START ++");  
}  
  
  
@Override  
  
public void onResume() {  
  
super.onResume();  
if (D) {  
Log.e(TAG, "+ ON RESUME +");  
Log.e(TAG, "+ ABOUT TO ATTEMPT CLIENT CONNECT +");  
  
}  
  
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);  
  
try {  
  
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);  
  
} catch (IOException e) {  
  
Log.e(TAG, "ON RESUME: Socket creation failed.", e);  
  
}  
mBluetoothAdapter.cancelDiscovery();  
try {  
  
btSocket.connect();  
  
Log.e(TAG, "ON RESUME: BT connection established, data transfer link open.");  
  
} catch (IOException e) {  
  
try {  
btSocket.close();  
  
} catch (IOException e2) {  
  
Log .e(TAG,"ON RESUME: Unable to close socket during connection failure", e2);  
}  
  
}  
  
  
// Create a data stream so we can talk to server.  
  
if (D)  
Log.e(TAG, "+ ABOUT TO SAY SOMETHING TO SERVER +");  
/* try { 
outStream = btSocket.getOutputStream(); 
 
} catch (IOException e) { 
Log.e(TAG, "ON RESUME: Output stream creation failed.", e); 

 
 
String message = "1"; 
 
byte[] msgBuffer = message.getBytes(); 
 
try { 
outStream.write(msgBuffer); 
 
} catch (IOException e) { 
Log.e(TAG, "ON RESUME: Exception during write.", e); 

*/  
  
}  
  
  
@Override  
  
public void onPause() {  
  
super.onPause();  
  
  
if (D)  
Log.e(TAG, "- ON PAUSE -");  
if (outStream != null) {  
try {  
outStream.flush();  
} catch (IOException e) {  
Log.e(TAG, "ON PAUSE: Couldn't flush output stream.", e);  
}  
  
}  
  
  
try {  
btSocket.close();  
} catch (IOException e2) {  
Log.e(TAG, "ON PAUSE: Unable to close socket.", e2);  
}  
  
}  
  
  
@Override  
  
public void onStop() {  
  
super.onStop();  
  
if (D)Log.e(TAG, "-- ON STOP --");  
  
}  
  
  
@Override  
  
public void onDestroy() {  
  
super.onDestroy();  
  
if (D) Log.e(TAG, "--- ON DESTROY ---");  
  
}  
  
}

可以看到,在这个程序中我直接把小车蓝牙模块的MAC地址给写进去了,其实更合理一点应该让程序运行后搜索周围蓝牙设备,然后选择需要连接的设备,获取它的MAC地址再连接,但是我为了图省事,就直接把我的小车的蓝牙MAC给定死了(反正也没那么多小车让我遥控~~~),这样一打开程序,手机将自动连接智能小车。

好了,手机端的开发到此介绍完毕~希望能为需要者提供一点帮助。

至于下位机部分呢就是通过监听蓝牙模块的socket ,一旦有数据传过来就读取蓝牙模块数据(读取到数据后)就执行相应操作    。要注意的是监听必须是单片机上电后就开始。如果这部分真觉得很不清楚,相应单片机附带的学习资料里大多都有和蓝牙模块编程相关代码(及视频),自己看看,只要是从蓝牙模块得到数据,这样(上位机和下位机就建立联系了,至于接下来就约定个指令集整个系统就出来了)。

Android蓝牙遥控器(通过手机蓝牙与蓝牙模块通信)相关推荐

  1. 三星android5.0 蓝牙,蓝牙5.0手机有哪些 蓝牙5.0和4.2的区别是什么【区别介绍】

    蓝牙5.0手机有哪些和4.2的区别是什么?相信小伙伴们一定很好奇,下面小编为大家带来了蓝牙5.0详细介绍说明,感兴趣的小伙伴赶紧跟着小编一起来看看吧. 今年3月,三星推出了最新的旗舰机GalaxyS8 ...

  2. html如何连接手机蓝牙,汽车蓝牙怎么连接手机,汽车蓝牙怎么打开图解

    汽车蓝牙怎么连接手机? 汽车蓝牙怎么打开?针对大家提出的的这两个问题,我们为大家分享一下操作指南. 1.把手机蓝牙和车载蓝牙都打开,且处于可发现状态: 3.选中手机中显示的车载蓝牙,点击车载蓝牙--蓝 ...

  3. 蓝牙遥控器 – 将手机模拟为键盘、鼠标、翻页笔、遥控器

    简介: 一直在寻找将手机模拟为鼠标和键盘的软件,对于有两部手机的人来说,这会使旧手机变废为宝,将其用作主力机的键盘,用来编辑文档写写东西还是非常方便的,一方面,备用机的整个手机屏幕都是键盘,双手操持打 ...

  4. mfc作为服务端,android作为客服端进行socket通讯,android在wifi下手机与电脑的socket通信...

    在 wifi 局域网下,手机可以和电脑通过 socket 通信.手机做服务端,电脑做客户端:也可 以反过来,电脑做服务端,手机做客户端. 下面介绍的是手机作为服务端,电脑使用 MFC 编程作为客户端, ...

  5. 背书神器,手机语音播报,蓝牙遥控器,文字合成语音,语音检索

    手机APP播音软件,后台按类别录入文章:  APP可以左右切换目录,上下切换文章:  暂停.继续播放:  麦克风语音输入检索文章! 可以把整本书装进APP. 所有的APP操作可通过蓝牙遥控器完成,再配 ...

  6. 树莓派学习3-树莓派蓝牙连接手机通信测试(蓝牙连接手机时断时序问题解决)

    通过上一篇文章学习,我们可以将树莓派的蓝牙连接到蓝牙音箱,进行语音播放.那么对于蓝牙配置和蓝牙控制软件更新,在此不再赘述. 1.树莓派连接手机蓝牙时断时续问题 原以为手机蓝牙和音箱蓝牙直接可以直接连接 ...

  7. Android 手机蓝牙遥控器解决方案

    驱动力(需求): 女朋友觉得躺床上用ipad看电视剧不爽,对睡姿要求太高,还容易砸到自己,所以提出需求,没辙,搞起来: 现有设备: Rk3288 开发版一个,dell 显示器一个,小音箱一对: 思路: ...

  8. Android蓝牙遥控器

    这是以前做的一个手机蓝牙遥控器,原本是用来控制一个微型四旋翼的.四旋翼做了第二版后改NRF2401控制了,所以这个程序最终还是没用,下面介绍一下这个程序的关键代码. 连接的对象是一个蓝牙4.0模块,连 ...

  9. Android 蓝牙遥控器的连接

    项目是TV端的,产品要求不经过设置界面,开机进入引导页,自动搜索蓝牙遥控器并且建立连接. 刚开始接手的时候以为会很快完成,无非就是调用API吗?可是事实不是这样,前后花了一些时间,才解决. 好了,当时 ...

最新文章

  1. Label控件属性AssociatedControlID
  2. Tensorflow杂记
  3. linux ftp 不能上传,linux ftp用户没法上传。
  4. UOJ#449. 【集训队作业2018】喂鸽子
  5. MySQL 5.6 双机热备
  6. nginx 转发_除了转发和负载均衡,nginx又一次让他玩出新高度
  7. Codeforces Round #694 (Div. 2) D. Strange Definition 质因子分解 + 平方数
  8. from + size must be less than or equal to: [10000] but was [10550]
  9. 子矩阵(NOIP2014 普及组第四题)
  10. FastDfs工作笔记002---SpringBoot集成FastDfs
  11. 自适应图片九宫格 css,高度自适应的九宫格效果
  12. 算法学习:蝙蝠算法简介
  13. android qq钱包接入,QQ
  14. 静态淘宝热卖界面(纯CSS)
  15. 计算机主机当机是什么意思,宕机什么意思_宕机是什么意思?_宕机的意思_电脑宕机是什么意思...
  16. 参与流片是一种怎样的体验?
  17. 2022天猫618预售活动攻略 淘宝618预售时间以及怎么玩
  18. Apache Doris 的一场编译之旅
  19. 再品Spring Ioc 和 Aop
  20. 哈尔滨理工计算机考研真题,哈尔滨理工大学考研真题各专业汇总

热门文章

  1. 论文笔记——Camouflaged Object Detection
  2. html文件如何恢复手机短信,如何恢复手机删除的短信?简单方法分享
  3. SVM支持向量机-软间隔与松弛因子(3)
  4. 构建高效的整车系统级别评估平台,百度安全自动驾驶风险安全研究亮相NDSS2022AutoSec...
  5. 《远程开关机工具 1.0》软件使用手册
  6. 基于three的晴雨表
  7. 【干货】7个面向产品经理的实用工具推荐
  8. 第5章:文件类工具软件
  9. 电脑显示器桌面最佳颜色对眼睛最好的最科学的
  10. dfs--选择困难症牛客