STM32 and BLE Bluetooth communication Android APP configuration (2)

The difficulty of affairs is far less than the fear of things

0. Preface

The preparatory work has been completed in the whole process of Android BLE Bluetooth configuration (1) Attached APP source code, here we get the name and address of the Bluetooth device to be connected, and need to complete the connection and data transmission function of the Bluetooth device .

1. Initialization interface

First, you need to complete the initialization of the controls contained in this interface. The code is as follows:

private TextView text1, text2;
private EditText editText;
private Button btn_send;
private String status = "Disconnected";
private final static String TAG = "hello";

//界面初始化
 private void initView() {
    
    
        text1 = findViewById(R.id.text1);
        text2 = findViewById(R.id.text2);
        editText = findViewById(R.id.edit_text);
        btn_send = findViewById(R.id.btn_send);

        text1.setText("状态:" + status);

        btn_send.setOnClickListener(this);
    }

text1The current connection status is displayed in the control , text2the received data is displayed in the control, edittextthe data to be sent is input in the control, and the control btn_sendis a send button

2. Get the data from the previous interface

First get the data from the previous interface, the code is as follows:

public static String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
public static String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";

private Bundle bundle;
private String name;
private String address;

bundle = getIntent().getExtras();
name = bundle.getString(EXTRAS_DEVICE_NAME);
address = bundle.getString(EXTRAS_DEVICE_ADDRESS);

nameThe name of the Bluetooth device is stored in , and addressthe address of the Bluetooth device is stored in .

3. Create a service class and inherit Service

In this article, a is created BlutoothBLEServiceand inherited Serviceto complete the initialization, connection, disconnection, read characteristic value, write characteristic value, set characteristic value change notification of the Bluetooth device, and obtain all services of the connected Bluetooth.

public class BlutoothBLEService extends Service {
    
    
			...............................
}

3.1 Bluetooth device initialization

public final static String ACTION_GATT_CONNECTED = "com.example.bluebledemo.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED = "com.example.bluebledemo.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluebledemo.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = "com.example.bluebledemo.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA = "com.example.bluebledemo.EXTRA_DATA";

private final static int STATE_DISCONNECTED = 0;
private final static int STATE_CONNECTING = 1;
private final static int STATE_CONNECTED = 2;

private final static String TAG = "hello";

private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;

//蓝牙初始化 在第二个界面中的ServiceConnection中调用
public boolean initialize() {
    
    
    if (mBluetoothManager == null) {
    
    
        mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
    
    
            Log.i(TAG, "initialize: mBluetoothManager 初始化失败");
            return false;
        }
    }
    mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
    
    
        Log.i(TAG, "initialize: mBluetoothAdapter 初始化失败");
        return false;
    }
    return true;
}

ServiceConnectionThe above code is executed in the callback function after the second interface successfully binds the service, which will be introduced in detail below, and the service will be explained in detail here.

3.2 Bluetooth device connection

private BluetoothGatt mBluetoothGatt;

//蓝牙连接外围设备
public boolean connect(final String address) {
    
    
    if (mBluetoothAdapter == null || address == null) {
    
    
        Log.i(TAG, "connect: BLE not init");
        return false;
    }
    if (mBluetoothDeviceAddress != null && mBluetoothGatt != null && mBluetoothDeviceAddress.equals(address)) {
    
    
        Log.i(TAG, "connect: Trying to use an existing mBluetoothGatt for connection");
        if (mBluetoothGatt.connect()) {
    
    
            mConnectionState = STATE_CONNECTING;
            return true;
        } else {
    
    
            return false;
        }
    }
    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    if (device == null) {
    
    
        Log.i(TAG, "connect: device not found");
        return false;
    }
    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
    Log.i(TAG, "connect: Trying to create a connection");
    mBluetoothDeviceAddress = address;
    mConnectionState = STATE_CONNECTING;
    return true;
}

In the second interface, an BlutoothBLEServiceobject of a class will be created, and then this method will be called and the address will be passed in, and the connection will be successful. mBluetoothGatt = device.connectGatt(this, false, mGattCallback)By binding the callback function, the subsequent operations in this section can be completed in the callback function.

3.3 Bluetooth device cancel connection

//取消连接
public void disconnect() {
    
    
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
    
    
        Log.i(TAG, "disconnect: BLE not init");
        return;
    }
    mBluetoothGatt.disconnect();
}

//关闭所有蓝牙连接
public void close() {
    
    
    if (mBluetoothGatt == null) {
    
    
        return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt = null;
}

You can also cancel the connection by calling this method through BlutoothBLEServicethe object of the class.

3.4 Reading characteristic values

//读取特征值
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
    
    
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
    
    
        Log.i(TAG, "readCharacteristic: BLE not init");
        return;
    }
    mBluetoothGatt.readCharacteristic(characteristic);
}

Automatically read the characteristic value once after the Bluetooth device is successfully connected.

3.5 Write characteristic value

//写入特征值
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
    
    
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
    
    
        Log.i(TAG, "writeCharacteristic: BLE not init");
        return;
    }
    mBluetoothGatt.writeCharacteristic(characteristic);
}

This is to complete the operation of writing data from the mobile APP to the Bluetooth device.

3.6 Set feature value change notification
This is very important, if not set, the mobile APP will not receive the data sent by the Bluetooth device.

//设置特征值变化通知
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristicNotification, boolean enabled) {
    
    
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
    
    
        Log.i(TAG, "setCharacteristicNotification: BLE not init");
        return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristicNotification, enabled);
    BluetoothGattDescriptor descriptor = characteristicNotification.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
    if (enabled) {
    
    
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
    } else {
    
    
        descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
    }
    mBluetoothGatt.writeDescriptor(descriptor);
}

This method is also called in the second interface, which UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"is HC-08the monitoring UUID of the Bluetooth device. If the Bluetooth device is not a model, please change it to the monitoring of the Bluetooth device you use UUID.

3.7 Get all services of connected Bluetooth

//获取已连接蓝牙的所有服务
public List<BluetoothGattService> getDupportedGattServices() {
    
    
    if (mBluetoothGatt == null) {
    
    
        return null;
    }
    return mBluetoothGatt.getServices();
}

Returns all services for connected bluetooth devices.

3.8 Read the RSSI value of the Bluetooth device

//读取RSSI
public void readRssi() {
    
    
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
    
    
        Log.i(TAG, "readRssi: BLE not init");
        return;
    }
    mBluetoothGatt.readRemoteRssi();
}

This method returns the signal value ( ) of the connected Bluetooth device RSSI.

3.9 Callback function for connected peripherals

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    
    
    @Override
    //重写 蓝牙连接状态
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    
    
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
    
            String intentAction;
            if (newState == BluetoothProfile.STATE_CONNECTED) {
    
    
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                mBluetoothGatt.discoverServices();   //发现服务
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
    
    
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                broadcastUpdate(intentAction);
            }
        }
    }

    //重写 蓝牙发现服务
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    
    
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
    
            broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            Log.i(TAG, "onServicesDiscovered: 蓝牙发现服务");
        } else {
    
    
            Log.i(TAG, "onServicesDiscovered: 蓝牙发现服务失败" + status);
        }

    }

    //重写 蓝牙读特征
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    
    
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
    
            Log.i(TAG, "onCharacteristicRead: is called");
            byte[] sucString = characteristic.getValue();
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    }

    //重写 蓝牙写特征
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    
    
        Log.i(TAG, "onCharacteristicWrite: 写数据成功");
    }

    //重写 蓝牙特征改变
    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    
    
        Log.i(TAG, "onCharacteristicChanged: changed changed changed changed changed ");
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }

    //重写 蓝牙读描述值
    @Override
    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
    
    
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
    
            Log.i(TAG, "onDescriptorRead: Read Read Read");
            byte[] desc = descriptor.getValue();
            if (desc == null) {
    
    
                Log.i(TAG, "onDescriptorRead: desc is null null null");
            }
        }
    }

    //重写 蓝牙写描述值
    @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
    
    
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
    
            Log.i(TAG, "onDescriptorWrite: Write Write Write");
        }
    }


    @Override
    public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
    
    
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
    
            Log.i(TAG, "onReliableWriteCompleted: onReliableWriteCompleted onReliableWriteCompleted onReliableWriteCompleted");
        }
    }

    //重写 获取蓝牙信号值
    @Override
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
    
    
        if (status == BluetoothGatt.GATT_SUCCESS) {
    
    
            Log.i(TAG, "onReliableWriteCompleted: RSSI RSSI RSSI");
            broadcastUpdate(ACTION_DATA_AVAILABLE, rssi);
        }
    }
};

BroadCastIn this callback function, you can get all the status of the connected Bluetooth device, including: whether the connection is successful, whether the data is sent successfully, whether the data is read successfully, etc., and then send the information through (broadcast) in this service, in In the second interface, set the listening receiver of the broadcast, and then complete the data transmission.

3.10 Send broadcast

//更新广播
private void broadcastUpdate(final String action) {
    
    
    final Intent intent = new Intent(action);
    sendBroadcast(intent);
}

//更新广播
private void broadcastUpdate(final String action, int rssi) {
    
    
    final Intent intent = new Intent(action);
    intent.putExtra(EXTRA_DATA, rssi);
    sendBroadcast(intent);
}

//更新广播
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
    
    
    final Intent intent = new Intent(action);
    final byte[] data = characteristic.getValue();
    //将data的数据传输给主空间中保存
    if (data != null && data.length > 0) {
    
    
        final StringBuilder stringBuilder = new StringBuilder(data.length);
        for (byte byteChar : data) {
    
    
            stringBuilder.append(String.format("%02X", byteChar));
            Log.i(TAG, "broadcastUpdate: byteChar is:" + byteChar);
        }
        intent.putExtra("BLE_BYTE_DATA", data);
        intent.putExtra(EXTRA_DATA, new String(data));
    }
    sendBroadcast(intent);

}

The data is sent out in the form of broadcast, and the corresponding broadcast is received by setting a filter in the second interface.

3.11 Get the object of the service

When the service is successfully bound in the second interface, an object of the service can be returned by calling this method.

public class LocalBinder extends Binder {
    
    
    public BlutoothBLEService getService() {
    
    
        return BlutoothBLEService.this;
    }

}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    
    
    return mBinder;
}

public boolean onUnbind(Intent intent) {
    
    
    close();
    return super.onUnbind(intent);
}

4. Binding service

After completing the code writing of the service, you need to bind the service in the second interface, and onCreatbind it in the method. The code is as follows:

Intent getServiceIntent = new Intent(this, BlutoothBLEService.class);
bindService(getServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

5. The callback function of the binding service

Whether the service is successfully bound, we can know in the callback function, the code is as follows:

private BlutoothBLEService mBlutoothBLEService;

//服务(BlutoothBLEService.class)连接 回调函数
private final ServiceConnection mServiceConnection = new ServiceConnection() {
    
    
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    
    
        mBlutoothBLEService = ((BlutoothBLEService.LocalBinder) service).getService();
        if (!mBlutoothBLEService.initialize()) {
    
    
            Log.i(TAG, "onServiceConnected: MainActivity BLE not init");
            finish();
        }
        Log.i(TAG, "onServiceConnected: 8888888888888");
        mBlutoothBLEService.connect(address);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    
    
        mBlutoothBLEService = null;
    }
};

If the binding is successful, first execute mBlutoothBLEService = ((BlutoothBLEService.LocalBinder) service).getService()to obtain the object of this service, and then execute mBlutoothBLEService.initialize()to initialize the service.

6. Register/unregister broadcast

//注册广播和IntentFilter
@Override
protected void onResume() {
    
    
    registerReceiver(mBroadCastReceiver, makeGattUpdateIntentFilter());
    if (mBlutoothBLEService != null) {
    
    
        Log.i(TAG, "onResume: 99999999999999");
        boolean res = mBlutoothBLEService.connect(address);
        Log.i(TAG, "onResume: " + res);
    }
    super.onResume();
}

//取消注册广播和IntentFilter
@Override
protected void onDestroy() {
    
    
    unregisterReceiver(mBroadCastReceiver);
    mBlutoothBLEService = null;
    super.onDestroy();
}

The above code utilizes registerReceiver(mBroadCastReceiver, makeGattUpdateIntentFilter())and unregisterReceiver(mBroadCastReceiver)methods to register and unregister the broadcast, and the following code is to set the broadcast receiver and filter.

//IntentFilter 设置过滤 与广播进行注册
public IntentFilter makeGattUpdateIntentFilter() {
    
    
    IntentFilter filter = new IntentFilter();
    filter.addAction(BlutoothBLEService.ACTION_GATT_CONNECTED);
    filter.addAction(BlutoothBLEService.ACTION_GATT_DISCONNECTED);
    filter.addAction(BlutoothBLEService.ACTION_GATT_SERVICES_DISCOVERED);
    filter.addAction(BlutoothBLEService.ACTION_DATA_AVAILABLE);
    return filter;
}
//设置广播接收 服务(BlutoothBLEService.class)传过来得信息
BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String actionString = intent.getAction();
        if (BlutoothBLEService.ACTION_GATT_CONNECTED.equals(actionString)) {
    
    	//蓝牙设备连接成功
            Log.i(TAG, "onReceive: " + name + " 连接成功");
            status = "Connected";
            updateConnectionState(status);
        } else if (BlutoothBLEService.ACTION_GATT_DISCONNECTED.equals(actionString)) {
    
    	//蓝牙设备连接失败
            Log.i(TAG, "onReceive: " + name + " 断开连接");
            status = "Disconnected";
            updateConnectionState(status);
        } else if (BlutoothBLEService.ACTION_GATT_SERVICES_DISCOVERED.equals(actionString)) {
    
    	//蓝牙设备设置服务
            Log.i(TAG, "onReceive: 广播接收到服务");
            displayGattServices(mBlutoothBLEService.getDupportedGattServices());
        } else if (BlutoothBLEService.ACTION_DATA_AVAILABLE.equals(actionString)) {
    
    	//蓝牙设备有数据提供
            Log.i(TAG, "onReceive: 有数据");
            displayData(intent.getExtras().getString(BlutoothBLEService.EXTRA_DATA), intent);
        }
    }
};

Among them displayGattServices(mBlutoothBLEService.getDupportedGattServices()), further completing the discovery service, displayData(intent.getExtras().getString(BlutoothBLEService.EXTRA_DATA), intent)further completing the processing of data reception, updateConnectionState(status)is to complete the update operation of the Bluetooth state, and these three codes will be described below.

7. Discover the connected Bluetooth device service

public static String CHARACTERISTIC_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
private BluetoothGattCharacteristic target_chara;
private Handler mHandler = new Handler();

//服务
public void displayGattServices(List<BluetoothGattService> gattServices) {
    
    
    if (gattServices == null) {
    
    
        return;
    }
    for (BluetoothGattService service : gattServices) {
    
    
        List<BluetoothGattCharacteristic> gattCharacteristics = service.getCharacteristics();
        for (final BluetoothGattCharacteristic characteristic : gattCharacteristics) {
    
    
            if (characteristic.getUuid().toString().equals(CHARACTERISTIC_UUID)) {
    
    
                mHandler.postDelayed(new Runnable() {
    
    
                    @Override
                    public void run() {
    
    
                        mBlutoothBLEService.readCharacteristic(characteristic);
                    }
                }, 200);
                mBlutoothBLEService.setCharacteristicNotification(characteristic, true);
                target_chara = characteristic;
            }
        }
    }
}

Among CHARACTERISTIC_UUIDthem HC-08is the read-write feature of the Bluetooth device UUID. If the model of the Bluetooth device used is different, please change it to the read-write feature of the Bluetooth device you are using. UUIDBased on this UUID, you can find the read-write feature of the Bluetooth device, so as to set the feature change notification and record this feature.

8. Reception of data

//接收的数据
public void displayData(String rev_string, Intent intent) {
    
    

    try {
    
    
        byte[] data = intent.getByteArrayExtra("BLE_BYTE_DATA");
        if (data == null) {
    
    
            Log.i(TAG, "displayData: data is empty");
            return;
        }
        rev_string = new String(data, 0, data.length, "GB2312");
    } catch (UnsupportedEncodingException e) {
    
    
        e.printStackTrace();
    }
    rev_str = rev_str + rev_string;
    runOnUiThread(new Runnable() {
    
    
        @Override
        public void run() {
    
    
            text2.setText(rev_str);
        }
    });
}

The above code completes the data reception, and puts the received data into the control text2for additional display.

9. Update Bluetooth connection status

private tempHandler myHandler = new tempHandler();
private String rev_str = "";

//更新蓝牙连接状态
private void updateConnectionState(String Status) {
    
    
    Message msg = new Message();
    msg.what = 1;
    Bundle bundle = new Bundle();
    bundle.putString("connect_state", status);
    msg.setData(bundle);
    myHandler.sendMessage(msg);
}

private class tempHandler extends Handler {
    
    
    @Override
    public void handleMessage(@NonNull Message msg) {
    
    
        switch (msg.what) {
    
    
            case 1:
                String str;
                str = msg.getData().getString("connect_state");
                text1.setText("状态:" + str);
                break;
        }
        super.handleMessage(msg);
    }
}

text1Update and display the current Bluetooth connection status in the control .

10. Send data

//发送数据线程
public class sendDataThread implements Runnable {
    
    

    public sendDataThread() {
    
    
        new Thread(this).start();
    }

    @Override
    public void run() {
    
    
        if (editText.getText() != null) {
    
    
            byte[] buff = null;
            try {
    
    
                buff = editText.getText().toString().getBytes("GB2312");
                Log.i(TAG, "run: " + buff.length);
            } catch (UnsupportedEncodingException e) {
    
    
                e.printStackTrace();
            }
            int[] sendDataLens = dataSparate(buff.length);
            for (int i = 0; i < sendDataLens[0]; i++) {
    
    
                byte[] data20 = new byte[20];
                for (int j = 0; j < 20; j++) {
    
    
                    data20[j] = buff[i * 20 + j];
                }
                target_chara.setValue(data20);
                mBlutoothBLEService.writeCharacteristic(target_chara);
            }
            if (sendDataLens[1] != 0) {
    
    
                byte[] lastData = new byte[sendDataLens[1]];
                for (int i = 0; i < sendDataLens[1]; i++) {
    
    
                    lastData[i] = buff[sendDataLens[0] * 20 + i];
                }
                if (lastData != null) {
    
    
                    target_chara.setValue(lastData);
                    mBlutoothBLEService.writeCharacteristic(target_chara);
                } else {
    
    
                    Log.i(TAG, "run: last是空的");
                }

            }

        }

    }
}

//发送数据实现点击事件
@Override
public void onClick(View v) {
    
    
    new sendDataThread();
}

//数据分包处理
private int[] dataSparate(int len) {
    
    
    int[] lens = new int[2];
    lens[0] = len / 20;
    lens[1] = len % 20;
    return lens;
}

By clicking the send button, a thread for sending data is created, and the sent data will be sub-packaged and sent sequentially to ensure that the data can be sent successfully even if the data is too large.

So far, the whole configuration process of Android's BLE Bluetooth (HC-08) has been explained in detail. If you have any questions, you can leave a message or private message me, and I will reply in time. If the above content is wrong, please feel free to enlighten me , here, I wish you success in your studies and a bright future~

How to get Android BLE Bluetooth (HC-08) source code for free
insert image description here

Guess you like

Origin blog.csdn.net/weixin_44355077/article/details/115429345