Android BLE教程(和单片机通信)

前言:若你你一个电子爱好者,若你酷爱编程,那我分享一个Android BLE application的开发方法,让你可以使用手机和单片机结合,使用手机控制单片机,做一些更有趣的东西,下面开始讲解如何开发一个Android BLE application,参考谷歌官方教程https://developer.android.com/guide/topics/connectivity/bluetooth-le.html

本文为封装之后的教程,可以更方便的更快速的搭建你的Android BLE application.当然我会把我的源码上传分享给大家。也可以参考官方提供的例程sdk/samples/android-18/legacy/BluetoothLeGatt

我的源码下载:http://download.csdn.net/detail/a353183177/8187165

1. 新建安卓工程

    打开EclipseFile->New->Android Application Project,在Application Name编辑框内填入Application名字,如:BleExampleMinimum Required SDK选择API18Android 4.3Target SDK也选择API18:Android 4.3,因为buletooth 4.0必须要Android 4.3及以上版本才能使用,其他默认不变,一直点Next按钮,直到出现Finish按钮,然后点Finish按钮。

2. 添加权限和服务

    在manifest file文件中添加:

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

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

<service android:name="com.elecfreaks.ble.BluetoothLeService" android:enabled="true"/>

3. 新建listView item布局文件

用于显示ListView中每一项的内容,我们这里使用自定义,这样可以让ListView中一项显示更多内容,item_list.xml内容如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"    

    >

    <TextView android:id="@+id/textViewDevName"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:textSize="24dp"/>

    <TextView android:id="@+id/textViewDevAddress"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:textSize="12dp"/>

</LinearLayout>

Copy我提供的源码BleExamplcom.elecfreaks.ble包到你的工程src目录里面,然后打开有错误提示的文件,按下shift+ctrl+O键。

4. 修改activity_main.xml增加scanButton按钮和bleDeviceListView

增加内容如下:

<Button

        android:id="@+id/scanButton"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:onClick="scanOnClick"

        android:text="scan" />

 

     <ListView

        android:id="@+id/bleDeviceListView"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/scanButton"

        android:layout_below="@+id/scanButton"

        android:layout_above="@+id/sendButton"

         >

    </ListView>

5. 在MainActivity.java中添加scanButton响应事件方法(onClick="scanOnClick")

public void scanOnClick(final View v){

 

}

6. 为MainActivity类添加成员

private Button scanButton;

private ListView bleDeviceListView;

private BLEDeviceListAdapter listViewAdapter;

private BluetoothHandler bluetoothHandler;

private boolean isConnected;

7. 在MainActivity.onCreate中设置成员的值

scanButton = (Button) findViewById(R.id.scanButton);

bleDeviceListView = (ListView)  findViewById(R.id.bleDeviceListView);

listViewAdapter = new BLEDeviceListAdapter(this);

bluetoothHandler = new BluetoothHandler(this);

bluetoothHandler.setOnConnectedListener(new  OnConnectedListener() {

@Override

public void onConnected(boolean isConnected) {

// TODO Auto-generated method stub

setConnectStatus(isConnected);

}

});

bluetoothHandler.setOnRecievedDataListener(new  OnRecievedDataListener() {

@Override

public void onRecievedData(byte[] bytes) {

// TODO Auto-generated method stub

System.out.printf("REC:");

for(byte b:bytes)

System.out.printf("%02X "b);

System.out.printf("\n");

}

});

8. 添加setConnectStatus方法

public void setConnectStatus(boolean isConnected){

this.isConnected = isConnected;

if(isConnected){

showMessage("Connection successful");

scanButton.setText("break");

}else{

bluetoothHandler.onPause();

     bluetoothHandler.onDestroy();

     scanButton.setText("scan");

}

}

private void showMessage(String str){

Toast.makeText(MainActivity.thisstr,  Toast.LENGTH_SHORT).show();

}

9. 在scanOnClick中添加内容

if(!isConnected){ bleDeviceListView.setAdapter(bluetoothHandler.getDeviceListAdapter());

bleDeviceListView.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View view,

int positionlong id) {

String buttonText = (String) ((Button)v).getText();

if(buttonText.equals("scanning")){

showMessage("scanning...");

return ;

}

BluetoothDevice device = bluetoothHandler.getDeviceListAdapter().getItem(position).device;

// connect

bluetoothHandler.connect(device.getAddress());

}

});

bluetoothHandler.setOnScanListener(new OnScanListener() {

@Override

public void onScanFinished() {

// TODO Auto-generated method stub

((Button)v).setText("scan");

((Button)v).setEnabled(true);

}

@Override

public void onScan(BluetoothDevice deviceint rssibyte[] scanRecord) {}

});

((Button)v).setText("scanning");

((Button)v).setEnabled(false);

bluetoothHandler.scanLeDevice(true);

}else{

setConnectStatus(false);

}

10. 发送数据

byte[] data = new byte[1];

data[0] = 0x02;

bluetoothHandler.sendData(data);

11. 接收数据

接收到数据时会调用bluetoothHandler.setOnRecievedDataListener()方法中设置的OnRecievedDataListener.onRecievedData(byte[] bytes)方法,其中bytes为接收到的数据

12. 通过协议发送数据给单片机

src目录新建Transmitter.java,添加带两个参数的构造函数,如下:

public Transmitter(Context context,  BluetoothHandler bluetoothHandler){

this.context = context;

this.mBluetoothHandler = bluetoothHandler;

}

添加sendData()方法:

private void sendData(byte[] bytes){

mBluetoothHandler.sendData(bytes);

}

添加sendPackage()方法:

public void sendPakege(byte[] databyte cmd){

byte[] bytes = new byte[data.length+6];

bytes[0] = (byte) 0xFA; // 数据头1

bytes[1] = (byte) 0xFB; // 数据头2

bytes[2] = (byte) 0xFC; // 数据头3

bytes[3] = (bytedata.length; // 数据长度

bytes[4] = cmd; // 指令

System.arraycopy(data, 0, bytes, 5, data.length);

for(int i=0; i<data.lengthi++){

bytes[data.length+5] ^= data[i]; // 校验和

}

sendData(bytes);

}

13. 通过协议接收单片机数据

src目录新建MyArray.java,用于连接两个数组,代码如下:

public class MyArray {

static public byte[] arrayCat(byte[] buf1,byte[] buf2){

    byte[] bufret=null;

    int len1 = 0;

    int len2 = 0;

    if(buf1 != null)

     len1 = buf1.length;

    if(buf2 != null)

     len2 = buf2.length;

    if(len1+len2 > 0)

     bufret = new byte[len1+len2];

    if(len1 > 0)

     System.arraycopy(buf1, 0, bufret, 0, len1);

    if(len2 > 0)

     System.arraycopy(buf2, 0, bufretlen1len2);

    return bufret;

    }

}

Copy我提供例程中的protocol.javasrc目录

添加成员private Protocol protocol;

在onCreate()中删除bluetoothHandler.setOnRecievedDataListener();

添加:

protocol = new Protocol(thisnew Transmitter(thisbluetoothHandler));

protocol.setOnReceivedDataListener(recListener);

在MainActivity中添加成员:

private static final boolean INPUT = false;

private static final boolean OUTPUT = true;

private static final boolean LOW = false;

private static final boolean HIGH = true;

private boolean digitalVal[];

private int analogVal[];

并且在onCreate中初始化:

digitalVal = new boolean[14];

analogVal = new int[14];

private OnReceivedRightDataListener recListener = new OnReceivedRightDataListener() {

@Override

public int onReceivedData(byte[] bytes) {

// TODO Auto-generated method stub

/*System.out.print("REC:");

    for(byte b:bytes)

    System.out.printf("%02X ", b);

    System.out.println("");*/

    

     byte pin;

     int pinValue;

    

     switch(bytes[4]){

     case Transmitter.READ_DATA:

if(bytes[Protocol.MODE_INDEX+5] == Protocol.DIGITAL){

     pin = bytes[Protocol.PIN_INDEX+5];

     pinValue = (short)  (bytes[Protocol.PINVALL_INDEX+5]);

     if(pinValue > 0){

     digitalVal[pin] = HIGH;

     }else{

     digitalVal[pin] = LOW;

     }

     }else if(bytes[Protocol.MODE_INDEX+5] ==  Protocol.ANALOG){

     pin = bytes[Protocol.PIN_INDEX+5];

     int high = bytes[Protocol.PINVALH_INDEX+5] & 0xff;

     int low = bytes[Protocol.PINVALL_INDEX+5] & 0xff;

     pinValue = high<<8 + low;

     System.out.println("low="+high+" high="+low+" val="+pinValue);

     analogVal[pin] = pinValue;

}

     break;

     case Transmitter.WRITE_DATA:

     break;

     default:break;

     }

    

return 0;

}

};

14. 使用协议发送数据

protocol.writeAnalogData(9, 20);

protocol.writeDigitalData(3, 1);

15. 使用协议接收数据

protocol.readAnalogDataCommand(9);

protocol.readDigitalDataCommand(3);

注意: 返回的数据由recListener 接收

16. 单片机端协议(arduino)

参考我提供的示例源码AndroidIOControl

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值