android手机通过串口蓝牙透传模块与AVR单片机通信实例。。。蓝牙服务程序案例
想了想,还是把这个项目记录一下,刚接触Android不久,这个算是第二个Android项目吧!不废话了,还是开始叙述一下项目吧!整个项目涉及Android的Wifi、Bluetooth通信,这里只介绍蓝牙部分:
一边是Android手机,另一端是串口蓝牙模块,具体是在淘宝买的(参考网址:http://item.taobao.com/item.htm?id=12792736263),串口蓝牙与AVR(ATMEGA 1280)相连。Android手机通过蓝牙向ATMEGA 1280发送指令信息来控制机器人做出相应动作。
主界面截图如下:两个EditText输入两个马达的速度,后面两个按钮设置马达转动的方向,点击发送指令开始发送,同时在下面的TextView中显示所发送的指令。
界面布局比较简单,就不再贴代码了。解释一下指令格式:前四位为固定值“CMD:”;接下来四位为ACK发送成功一次,ACK累加1;接下来四位设置第一个马达,第一位设置方向,后三位为速度;最后四位就是第二个马达的设置。
Android要使用蓝牙,首先要在AndroidManifest.xml文件中进行如下配置:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
在AndroidManifest.xml里面注册Service
<service android:name=".BluetoothServe.BluetoothService" android:enabled="true"></service>
1、首先是主Activity,主界面如上图,点击菜单,可以扫描远端蓝牙设备,可以设置本机蓝牙可见性,代码如下:
package com.example.android.BluetoothChat;import java.io.IOException;import com.example.android.BluetoothServe.BluetoothService;import com.example.android.BluetoothServe.BluetoothData;import android.app.Activity;import android.app.AlertDialog;import android.app.Dialog;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothSocket;import android.content.ComponentName;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class BluetoothChat extends Activity {/** Called when the activity is first created. */private static final String TAG = "BlutoothTest";private static final boolean D = true ;private Button btF1,btF2,btW1,btW2,sendCMD;private TextView mTextView;private TextView commandview,ackview;private EditText edit1,edit2;private BluetoothAdapter myBluetoothAdapter = null;private BluetoothSocket btSocket = null;private static final int REQUEST_CONNECT_DEVICE = 1;private String BackACK = "ACK:"; private String speed1,speed2;private int left = 1,right=1;private static int count = 1;private BluetoothData bluetoothData;//此处用于启动蓝牙服务程序 private ServiceConnection connection=new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName arg0, IBinder service) {bluetoothData = (BluetoothData)service; }@Overridepublic void onServiceDisconnected(ComponentName arg0) {bluetoothData = null;}}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //本地蓝牙启动 myBluetoothAdapter =BluetoothAdapter.getDefaultAdapter(); OpenBluetooth(myBluetoothAdapter); try { bindService(new Intent(BluetoothChat.this,BluetoothService.class), connection, Context.BIND_AUTO_CREATE);} catch (Exception e) {// TODO: handle exception} btF1 = (Button)findViewById(R.id.bt4); btF2 = (Button)findViewById(R.id.bt5); btW1 = (Button)findViewById(R.id.bt1); btW2 = (Button)findViewById(R.id.bt2); edit1 = (EditText) findViewById(R.id.edit1); edit2 = (EditText) findViewById(R.id.edit2); mTextView =(TextView) findViewById(R.id.mytext); commandview = (TextView) findViewById(R.id.commandview); sendCMD = (Button)findViewById(R.id.bt3); ackview = (TextView) findViewById(R.id.ackview); btF1.setOnClickListener(new myButtonClickListener()); btF2.setOnClickListener(new myButtonClickListener()); btW1.setOnClickListener(new myButtonClickListener()); btW2.setOnClickListener(new myButtonClickListener()); sendCMD.setOnClickListener(new OnClickListener() { @Overridepublic void onClick(View v) {// TODO Auto-generated method stubString command = "CMD:"; try { count = bluetoothData.getACK();} catch (Exception e) {// TODO: handle exception}speed1 = edit1.getText().toString();speed2 = edit2.getText().toString();command += bluetoothData.CreateCMD(speed1, speed2, String.valueOf(count), left, right);try {bluetoothData.SendMessage(command);//bluetoothData.getACK();} catch (Exception e) {// TODO: handle exception}commandview.setText(command);//count++;}}); } private void OpenBluetooth(BluetoothAdapter myBluetoothAdapter){//本地蓝牙启动 if(myBluetoothAdapter == null) { Toast.makeText(this,"蓝牙不可用", Toast.LENGTH_LONG).show(); //finish(); return; } if(!myBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(enableIntent); }} class myButtonClickListener implements OnClickListener{@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()){ case R.id.bt1: left=0; mTextView.setText("马达一向后"); break; case R.id.bt2: right=0; mTextView.setText("马达二向后"); break; case R.id.bt4: left=1; mTextView.setText("马达一向前"); break; case R.id.bt5: right=1; mTextView.setText("马达二向前"); break; default: break;}}} @Overrideprotected void onStart() {// TODO Auto-generated method stubsuper.onStart();if(D){Log.e(TAG, "++ ON START ++");Log.e(TAG, "ABOUT TO ATTEMPT CLIENT CONNECT");}} @Override protected void onResume(){ super.onResume(); new Thread() { public void run() { try { if(bluetoothData.getMessage() != null) BackACK += bluetoothData.getMessage(); ackview.setText(BackACK); } catch (Exception e) { // TODO: handle exception } try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); if(D){ Log.e(TAG, "++ ON RESUME ++"); } }public void DisplayMessage(String str){ Toast.makeText(this, str, Toast.LENGTH_LONG).show();} //创建对话框的方法 @Override protected Dialog onCreateDialog(int id) { // TODO Auto-generated method stub AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(BackACK) .setCancelable(false) .setPositiveButton("YES", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub //MyActivity.this.finish(); dialog.dismiss(); } }); AlertDialog alert = builder.create(); return alert; //return super.onCreateDialog(id); }@Overrideprotected void onPause() { // TODO Auto-generated method stubsuper.onPause();if(D){Log.e(TAG, "++ ON PAUSE ++");}}@Overrideprotected void onStop() {// TODO Auto-generated method stubsuper.onStop();//count = 1;if(D){Log.e(TAG, "++ ON STOP ++");}}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubunbindService(connection);super.onDestroy();//count = 1;if (D){Log.e(TAG, "++ ON DESTROY ++");}try {if(btSocket != null) btSocket.close();} catch (IOException e) { Log.e(TAG, "Close failed");}} @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.option_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.scan: // Launch the DeviceListActivity to see devices and do scan Intent serverIntent = new Intent(this, DeviceListActivity.class); startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE); return true; case R.id.discoverable: // Ensure this device is discoverable by others ensureDiscoverable(); return true; } return false; } //设置本机蓝牙可见性 private void ensureDiscoverable() { if(D) Log.d(TAG, "ensure discoverable"); if (myBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent); } }}
开始是将蓝牙服务程序作为主界面的一个进程,结果运行速度比较慢,由于程序一启动就进行蓝牙连接,所以主进程被阻塞,导致程序启动后过好一会才有反应,而且手机一旦锁屏后,蓝牙连接被断开,解锁后又重新进行 蓝牙连接,觉得很不方便,效率不高。所以把整个蓝牙的连接建立、蓝牙数据传送以及其他处理放到service里面,程序启动后,启动蓝牙服务程序一直处于后台运行,当要传递数据时直接调用service里面的服务即可。
2、下面是蓝牙服务程序
package com.example.bote.BluetoothServe;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.reflect.Method;import java.util.UUID;import android.app.Service;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothSocket;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;import android.widget.Toast;public class BluetoothService extends Service {private static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");private static String address = "00:12:08:21:06:01";//远端蓝牙地址private BluetoothAdapter myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //获取本地蓝牙信息private BluetoothDevice mDevice = myBluetoothAdapter.getRemoteDevice(address); //获取远端蓝牙信息private BluetoothSocket btSocket = null;private InputStream inputStream = null;private OutputStream outputStream = null;private int temp = 0;private String CMD = null;private String BackACK = null;private static final String TAG = "BlutoothService";private int ACK=0;/*Binder类实现BluetoothData接口*/public class myIBinder extends Binder implements BluetoothData {BluetoothService getService() {return BluetoothService.this;}/*发送指令函数,参数为指令信息,发送成功返回true,否则返回false*/public boolean SendMessage(String str) {// TODO Auto-generated method stubbyte[] msgBuffer;msgBuffer = str.getBytes();try {if (btSocket != null) {outputStream = btSocket.getOutputStream();//打开输出流}} catch (IOException e) {Log.e(TAG, "ON Resume:output stream creation failed");}try {outputStream.write(msgBuffer);ACK++; //发送成功后,ACK自动加一if(ACK>9999){ACK=0;}return true;} catch (IOException e) {// TODO: handle exceptionLog.e(TAG, "On Resume:Exception during write");DisplayMessage("发送失败!");}return false;}/*获取ACK信息并返回*/public String getMessage() {// TODO Auto-generated method stubif (BackACK != null) {return BackACK;}return null;}/*初始速度设置函数,向船发送指令,设置两个马达的初始速度,发送成功返回true,否则返回false*/public boolean Sendmessagelr(int left, int right) {// TODO Auto-generated method stubString string = null;string=CreateCMD(String.valueOf(left),String.valueOf(right),String.valueOf(ACK),1,1);SendMessage(string);return false;}/*生成指令函数,通过传递速度、ACK以及方向信息来生成一个指令 * 指令的前4位表示ACK,不足四位的前面补零 * 接下来4位为第一个马达信息,第一位表示方向,为0表示反转,为1表示正转,后三位为速度大小,不足3位的前面补零 * 最后4位为第二个马达信息,第一位表示方向,为0表示反转,为1表示正转,后三位为速度大小,不足3位的前面补零*/public String CreateCMD(String speed1, String speed2, String ACK,int left, int right) {// TODO Auto-generated method stubtemp = ACK.length();while (temp < 4){ACK='0'+ACK;temp++;}CMD = ACK;temp = speed1.length();while (temp < 3){speed1='0'+speed1;temp++;}CMD += (left+speed1);temp = speed2.length();while (temp < 3){speed2='0'+speed2;temp++;}CMD += (right+speed2);return CMD+'!'; }}private IBinder mBinder = new myIBinder();@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubSystem.out.println("onBind Service");return mBinder;}@Overridepublic void onCreate() {// TODO Auto-generated method stubSystem.out.println("onCreate Service");DisplayMessage("Bluetooth Service Start");DisplayMessage("正在尝试连接蓝牙设备" + mDevice + "请稍后···");/*将蓝牙连接建立过程放到新线程中*/new Thread() {public void run() {//如果本地蓝牙尚未开启,无法建立连接,必须等待蓝牙开启if (!myBluetoothAdapter.isEnabled()) {try {Log.e(TAG, "线程休眠");sleep(8000); //线程睡眠,等待蓝牙开启} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}Log.e(TAG, "线程开始");try {btSocket = mDevice.createRfcommSocketToServiceRecord(myUUID); //创建socket通信} catch (IOException e) {// TODO Auto-generated catch blockDisplayMessage("创建套接字失败!");e.printStackTrace();}try {connectDevice(); //调用蓝牙连接函数来建立连接} catch (Exception e) {// TODO: handle exception}}}.start();super.onCreate();}@Overridepublic void onDestroy() {// TODO Auto-generated method stubSystem.out.println("onDestroy Service");super.onDestroy();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubLog.i("LocalService", "Received Start ID" + startId + ":" + intent);System.out.println("onStartCommand Service");return START_STICKY;}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubSystem.out.println("onStart Service");getMessageThread getMessage = new getMessageThread();getMessage.start();super.onStart(intent, startId);}@Overridepublic boolean onUnbind(Intent intent) {// TODO Auto-generated method stubSystem.out.println("onUnbind Service");return super.onUnbind(intent);}public void DisplayMessage(String str) {Toast.makeText(this, str, Toast.LENGTH_LONG).show(); //显示Toast信息}protected void connectDevice() {try {// 连接建立之前的先配对if (mDevice.getBondState() == BluetoothDevice.BOND_NONE) {Method creMethod = BluetoothDevice.class.getMethod("createBond");Log.e("TAG", "开始配对");creMethod.invoke(mDevice);} else {}} catch (Exception e) {// TODO: handle exceptionDisplayMessage("无法配对!");e.printStackTrace();}myBluetoothAdapter.cancelDiscovery();try {btSocket.connect();DisplayMessage("连接成功!");} catch (IOException e) {// TODO: handle exceptionDisplayMessage("连接失败!");try {btSocket.close();} catch (IOException e2) {// TODO: handle exceptionLog.e(TAG, "Cannot close connection when connection failed");}}} //从蓝牙端获取信息类,这个方法不一定对或者并没有完善public class getMessageThread extends Thread {public void run() {if (btSocket != null) {try {inputStream = btSocket.getInputStream();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}try {BackACK = Integer.toString(inputStream.read());} catch (Exception e) {// TODO: handle exception}}}}
/* * 蓝牙服务接口 * */package com.example.bote.BluetoothServe;public interface BluetoothData {/*发送指令函数,参数为指令信息,发送成功返回true,否则返回false*/public boolean SendMessage(String str);/*从蓝牙端获取信息函数,返回的信息为获取到的字符窜*/public String getMessage();/*初始速度设置函数,向船发送指令,设置两个马达的初始速度,发送成功返回true,否则返回false*/public boolean Sendmessagelr(int left, int right);/*生成指令函数,通过传递速度、ACK以及方向信息来生成一个指令*/public String CreateCMD(String speed1, String speed2, String ACK,int left, int right);}
4、如果这样直接制定远端蓝牙的地址建立连接,那么当要改变地址时,得手动修改源程序的蓝牙地址,这样显得不人性化,所以添加一个扫描蓝牙地址的功能。扫描程序没必要自己写,下面是Android自带的例子BluetoothChat里面的DeviceListActivity.java的内容,直接用就行,不过,有个地方需要修改一下,就是当点击扫描到的蓝牙地址时,需要重新启动蓝牙服务程序,直接调用service里面的OnStart()方法就行。修改如下:
// The on-click listener for all devices in the ListViews private OnItemClickListener mDeviceClickListener = new OnItemClickListener() { public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) { // Cancel discovery because it's costly and we're about to connect mBtAdapter.cancelDiscovery(); // Get the device MAC address, which is the last 17 chars in the View String info = ((TextView) v).getText().toString(); String address = info.substring(info.length() - 17); BluetoothService nService = new BluetoothService(); // Create the result Intent and include the MAC address Intent intent = new Intent(); intent.putExtra(EXTRA_DEVICE_ADDRESS, address); nService.onStart(intent,1); //启动蓝牙服务 setResult(Activity.RESULT_OK, intent); finish(); } };
这是几个月前做的项目,现在来梳理,可能有些地方有问题。还有此处的重点是向单片机发送信息,并没有处理从单片机回送的信息,因此简化了蓝牙接收信息的过程,当然处理起来也不难,网上有很多教程。请多多指教~
更多相关文章
- Android 获取无线蓝牙MAC信息代码
- Android查看手机线程指令
- Android smali语言功能指令详细介绍
- Android实现蓝牙打印
- 根据文件名称修改安卓默认的蓝牙接收文件地址
- Android 中文API (65) ―― BluetoothClass[蓝牙]
- adb pm 指令介绍
- android bluetooth UUID蓝牙查询表
- Android 蓝牙(BLE)连接,发送,接收消息